package com.molichuxing.services.business.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.molichuxing.framework.dto.UploadFileRequestDto;
import com.molichuxing.framework.dto.UploadFileResponseDto;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.result.ResponseResult;
import com.molichuxing.framework.utils.*;
import com.molichuxing.services.business.dto.request.create.*;
import com.molichuxing.services.business.dto.response.ContractImageBizDto;
import com.molichuxing.services.business.dto.response.ContractPurchaseBizDto;
import com.molichuxing.services.business.service.ContractBizService;
import com.molichuxing.services.infrastructure.convertor.Convert;
import com.molichuxing.services.infrastructure.dto.request.create.ContractCreateDto;
import com.molichuxing.services.infrastructure.dto.request.create.ContractImageCreateDto;
import com.molichuxing.services.infrastructure.dto.response.*;
import com.molichuxing.services.infrastructure.service.*;
import com.molichuxing.services.property.*;
import com.molichuxing.services.sdk.ESignLib;
import com.molichuxing.services.util.CompanySealDataCacheUtil;
import com.molichuxing.services.util.FileEhCacheUtil;
import com.timevale.esign.sdk.tech.bean.PosBean;
import com.timevale.esign.sdk.tech.bean.SignPDFStreamBean;
import com.timevale.esign.sdk.tech.bean.result.FileCreateFromTemplateResult;
import com.timevale.esign.sdk.tech.bean.result.FileDigestSignResult;
import com.timevale.esign.sdk.tech.impl.constants.SignType;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;


/**
 * <p>
 * 合同 服务实现类
 * </p>
 *
 * @author zhaopenghui
 * @since 2019-10-09
 */
@Service("contractBizService")
public class ContractBizServiceImpl implements ContractBizService {
    private static final Logger logger = LoggerFactory.getLogger(ContractBizServiceImpl.class);

    private static final String YES = "Y";
    private static final String NO = "N";

    //里程包合同前缀
    private static final String PREFIX = "[LC]";
    @Autowired
    ContractService contractService;
    @Autowired
    EsignAccountService esignAccountService;
    @Autowired
    EsignCompanyService esignCompanyService;
    @Autowired
    EsignDealerService esignDealerService;
    @Autowired
    ContractTemplateService contractTemplateService;
    @Autowired
    ContractLogService contractLogService;
    @Autowired
    ContractImageService contractImageService;
    @Autowired
    private CompanySealDataCacheUtil companySealDataCacheUtil;

    @Autowired
    FileEhCacheUtil fileEhCacheUtil;
    @Value("${contract.file.path}")
    private String CONTRACT_FILE_PATH;
    @Value("${profiles.active.explain}")
    private String ACTIVE_EXPLAIN;
    @Value("${vehicle.recovery.fee}")
    private String VEHICLE_RECOVERY_FEE;
    @Value("${overdue.labor.cost}")
    private String OVERDUE_LABOR_COST;
    @Value("${towing.fee}")
    private String TOWING_FEE;


    /**
     * 添加专属合同
     *
     * @param dto
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean createExclusivelContract(ContractExclusivelBizCreateDto dto) throws Exception {
        logger.info("createExclusivelContract，专属合同入参：" + JSONObject.toJSONString(dto));
        ContractCreateEnum contractRequestEnum = dto.getContractCreateEnum();
        if (null == contractRequestEnum) {
            return false;
        }
        UploadFileRequestDto uploadFileRequestDto = dto.getUploadFileRequestDto();

        if (ContractCreateEnum.EXTRACT_VEHICLE == contractRequestEnum) {
            ContractGeneralBizCreateDto contractGeneralBizCreateDto = dto.getContractGeneralBizCreateDto();
            ContractSupplementBizCreateDto contractSupplementBizCreateDto = dto.getContractSupplementBizCreateDto();
            ContractDeliveryBizCreateDto contractDeliveryBizCreateDto = dto.getContractDeliveryBizCreateDto();
            Map<Integer, Integer> contractTemplateMap = getContractTemplateMap(ContractBusinessTypeEnum.EXCLUSIVEL.getValue());

            //通用条款 和 保证合同
            Integer contractMasterId = contractTemplateMap.get(ContractTypeEnum.COMMON_CONTRACT.getValue());
            logger.info("通用条款模板" + contractMasterId);
            if (contractMasterId != null) {
                contractGeneralBizCreateDto.setContractMasterId(contractMasterId);
                contractGeneralBizCreateDto.setVehicleRecoveryFee(VEHICLE_RECOVERY_FEE);

                ResponseResult<String> generalAndGuaranteeResponse = createGeneralAndGuarantee(contractGeneralBizCreateDto, uploadFileRequestDto);
                if (generalAndGuaranteeResponse.getCode() != 200) {
                    return false;
                }
            }

            //专用条款 和 补充协议
            Integer contractDedicatedId = contractTemplateMap.get(ContractTypeEnum.DEDICATED_CONTRACT.getValue());
            Integer contractSupplementId = contractTemplateMap.get(ContractTypeEnum.SUPPLEMENT_CONTRACT.getValue());
            logger.info("专用条款模板" + contractDedicatedId + ",补充协议模板" + contractSupplementId);
            if (contractDedicatedId != null || contractSupplementId != null) {
                contractSupplementBizCreateDto.setContractDedicatedId(contractDedicatedId);
                contractSupplementBizCreateDto.setContractSupplementId(contractSupplementId);

                ResponseResult<Boolean> specialAndSupplementResponse = createSpecialAndSupplement(contractSupplementBizCreateDto, uploadFileRequestDto);
                if (specialAndSupplementResponse.getCode() != 200) {
                    return false;
                }
            }

            //提车单
            Integer contractDeliveryId = contractTemplateMap.get(ContractTypeEnum.CAR_CONTRACT.getValue());
            logger.info("提车单模板" + contractDeliveryId);
            if (contractDeliveryId != null) {
                ResponseResult<Boolean> deliveryResponse = createDelivery(contractDeliveryBizCreateDto, uploadFileRequestDto);
                if (deliveryResponse.getCode() != 200) {
                    return false;
                }
            }
            return true;
        } else if (ContractCreateEnum.RETURN_VEHICLE == contractRequestEnum) {
            ContractDeliveryBizCreateDto contractDeliveryBizCreateDto = dto.getContractDeliveryBizCreateDto();
            Map<Integer, Integer> contractTemplateMap = getContractTemplateMap(ContractBusinessTypeEnum.EXCLUSIVEL.getValue());

            //还车单
            ResponseResult<Boolean> deliveryResponse = createDelivery(contractDeliveryBizCreateDto, uploadFileRequestDto);
            if (deliveryResponse.getCode() != 200) {
                return false;
            }

            return true;
        } else {
            return false;
        }
    }

    /**
     * 创建订阅合同
     *
     * @param dto
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean createSubscribeContract(ContractSubscribeBizCreateDto dto) throws Exception {
        logger.info("createSubscribeContract，订阅合同入参：" + JSONObject.toJSONString(dto));
        ContractCreateEnum contractRequestEnum = dto.getContractCreateEnum();
        if (null == contractRequestEnum) {
            return false;
        }
        UploadFileRequestDto uploadFileRequestDto = dto.getUploadFileRequestDto();

        if (ContractCreateEnum.EXTRACT_VEHICLE == contractRequestEnum) {
            ContractMileageBagBizCreateDto contractMileageBagBizCreateDto = dto.getContractMileageBagBizCreateDto();
            ContractDeliveryBizCreateDto contractDeliveryBizCreateDto = dto.getContractDeliveryBizCreateDto();
            Map<Integer, Integer> contractTemplateMap = getContractTemplateMap(ContractBusinessTypeEnum.SUBSCRIBE.getValue());

            //订阅里程
            Integer contractMileageBagId = contractTemplateMap.get(ContractTypeEnum.MILEAGE_BAG_CONTRACT.getValue());
            logger.info("订阅里程模板" + contractMileageBagId);
            if (contractMileageBagId != null) {
                contractMileageBagBizCreateDto.setContractMasterId(contractMileageBagId);
                contractMileageBagBizCreateDto.setOverdueLaborCost(OVERDUE_LABOR_COST);
                contractMileageBagBizCreateDto.setTowingFee(TOWING_FEE);

                ResponseResult<String> mileageBagResponse = createMileageBag(contractMileageBagBizCreateDto, uploadFileRequestDto);
                if (mileageBagResponse.getCode() != 200) {
                    return false;
                }
            }

            //提车单
            Integer contractMileageBagCarId = contractTemplateMap.get(ContractTypeEnum.MILEAGE_BAG_CAR_CONTRACT.getValue());
            logger.info("提车单模板" + contractMileageBagCarId);
            if (contractMileageBagCarId != null) {
                ResponseResult<Boolean> deliveryResponse = createDelivery(contractDeliveryBizCreateDto, uploadFileRequestDto);
                if (deliveryResponse.getCode() != 200) {
                    return false;
                }
            }
            return true;
        } else if (ContractCreateEnum.RETURN_VEHICLE == contractRequestEnum) {
            ContractDeliveryBizCreateDto contractDeliveryBizCreateDto = dto.getContractDeliveryBizCreateDto();
            Map<Integer, Integer> contractTemplateMap = getContractTemplateMap(ContractBusinessTypeEnum.SUBSCRIBE.getValue());

            //还车单
            Integer contractMileageBagReturnId = contractTemplateMap.get(ContractTypeEnum.MILEAGE_BAG_RETURN_CAR.getValue());
            logger.info("还车单模板" + contractMileageBagReturnId);
            if (contractMileageBagReturnId != null) {
                ResponseResult<Boolean> deliveryResponse = createDelivery(contractDeliveryBizCreateDto, uploadFileRequestDto);
                if (deliveryResponse.getCode() != 200) {
                    return false;
                }
            }
            return true;
        } else if (ContractCreateEnum.RENEW == contractRequestEnum) {
            ContractMileagePurchasedBizCreateDto contractMileagePurchasedBizCreateDto = dto.getContractMileagePurchasedBizCreateDto();
            Map<Integer, Integer> contractTemplateMap = getContractTemplateMap(ContractBusinessTypeEnum.SUBSCRIBE.getValue());

            //续订
            Integer contractMileageBagRenewId = contractTemplateMap.get(ContractTypeEnum.MILEAGE_BAG_RENEW_CONTRACT.getValue());
            logger.info("续订模板" + contractMileageBagRenewId);
            if (contractMileageBagRenewId != null) {
                contractMileagePurchasedBizCreateDto.setContractType(ContractTypeEnum.MILEAGE_BAG_RENEW_CONTRACT.getValue());
                ResponseResult<String> purchasedResponse = createPurchased(contractMileagePurchasedBizCreateDto, uploadFileRequestDto);
                if (purchasedResponse.getCode() != 200) {
                    return false;
                }
            }
            return true;
        } else if (ContractCreateEnum.PURCHASE == contractRequestEnum) {
            ContractMileagePurchasedBizCreateDto contractMileagePurchasedBizCreateDto = dto.getContractMileagePurchasedBizCreateDto();
            Map<Integer, Integer> contractTemplateMap = getContractTemplateMap(ContractBusinessTypeEnum.SUBSCRIBE.getValue());

            //加购
            Integer contractMileageBagPurchasedId = contractTemplateMap.get(ContractTypeEnum.MILEAGE_BAG_PURCHASED_CONTRACT.getValue());
            logger.info("加购模板" + contractMileageBagPurchasedId);
            if (contractMileageBagPurchasedId != null) {
                contractMileagePurchasedBizCreateDto.setContractType(ContractTypeEnum.MILEAGE_BAG_PURCHASED_CONTRACT.getValue());
                contractMileagePurchasedBizCreateDto.setMinWithin("2");
                ResponseResult<String> purchasedResponse = createPurchased(contractMileagePurchasedBizCreateDto, uploadFileRequestDto);
                if (purchasedResponse.getCode() != 200) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }


    /**
     * 生成通用条款和保证合同
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public ResponseResult<String> createGeneralAndGuarantee(ContractGeneralBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        ResponseResult<String> response = createGeneralAndGuaranteeContract(dto, uploadFileRequestDto);
        if (response.getCode() != 200) {
            Long orderCode = dto.getOrderCode();
            Integer businessType = dto.getBusinessType();
            ContractLogDto contractLogDto = createContractLog(orderCode, businessType, null, null, response.getMessage(), false);
            contractLogService.createContractLog(contractLogDto);
            DingTalkUtil.exceptionSend(ACTIVE_EXPLAIN + "订单号：" + orderCode + "生成通用条款异常：" + response.getMessage());
        }
        return response;
    }

    /**
     * 创建合同
     *
     * @param dto
     * @return
     */
    private ResponseResult<String> createGeneralAndGuaranteeContract(ContractGeneralBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        ResponseResult<String> response = new ResponseResult<String>();
        long startTime = System.currentTimeMillis(); // 开始时间
        logger.info("生成通用条款和保证合同入参：》》》》》》》》" + JSONObject.toJSONString(dto));
        // 查询该订单是否已经生成过合同
        checkContractIsExist(dto);

        //根据用户身份证号和姓名查询该用户的印章信息
        EsignAccountDto esignAccountB = getEsignAccount(dto.getPartyBName(), dto.getPartyBCard());
        //根据甲方公司id查询公司印章信息
        EsignCompanyDto esignCompanyA = getEsignCompany(dto.getPartyAId().intValue(), EsignCompanyTypeEnum.ASSET_COMPANY.getValue());
        //担保人印章信息
        EsignAccountDto esignAccountBB = null;
        if (dto.getIsWarrantor() == 1) {
            esignAccountBB = getEsignAccount(dto.getWarrantorName(), dto.getWarrantorCard());
        }

        //获取模板
        List<Integer> templateList = getTemplateList(dto);
        //根据id获取合同模板
        List<ContractTemplateDto> Templates = getContractTemplateList(templateList);
        //获取合同编号
        getContractNumber(dto);
        //生成合同并盖章
        response = createGeneralAndGuarantee(esignAccountB, esignAccountBB
                , esignCompanyA, Templates, dto, uploadFileRequestDto);
        if (response.getCode() != 200) {
            return response;
        }

        long endTime = System.currentTimeMillis(); // 开始时间
        logger.info("生成通用条款和保证合同用时：》》》》》》》》" + (endTime - startTime) + "ms");
        logger.info("生成通用条款和保证合同出参：》》》》》》》》" + JSONObject.toJSONString(response));
        return response;
    }

    /**
     * 生成专用条款和补充协议
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public ResponseResult<Boolean> createSpecialAndSupplement(ContractSupplementBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        ResponseResult<Boolean> response = createSpecialAndSupplementContract(dto, uploadFileRequestDto);
        if (response.getCode() != 200) {
            Long orderCode = dto.getOrderCode();
            Integer businessType = dto.getBusinessType();
            ContractLogDto contractLogDto = createContractLog(orderCode, businessType, null, null, response.getMessage(), false);
            contractLogService.createContractLog(contractLogDto);
            DingTalkUtil.exceptionSend(ACTIVE_EXPLAIN + "订单号：" + orderCode + "生成专用条款和补充协议异常：" + response.getMessage());
        }
        return response;
    }


    /**
     * 创建合同
     *
     * @param dto
     * @return
     */
    private ResponseResult<Boolean> createSpecialAndSupplementContract(ContractSupplementBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        long startTime = System.currentTimeMillis(); // 开始时间
        logger.info("生成专用条款和补充协议入参：》》》》》》》》" + JSONObject.toJSONString(dto));
        ResponseResult<Boolean> response = new ResponseResult<Boolean>();

        Integer contractSupplementId = dto.getContractSupplementId();
        // 查询该订单是否已经生成过合同
        if (contractSupplementId != null) {
            getContractIsExist(dto.getOrderCode(), ContractTypeEnum.SUPPLEMENT_CONTRACT.getValue());
        }

        //专用条款和补充协议计算数据
        dto = getUsedcarSpecialTemplateDto(dto);

        //根据用户身份证号和姓名查询该用户的印章信息
        EsignAccountDto esignAccountB = getEsignAccount(dto.getPartyBName(), dto.getPartyBCard());
        //根据甲方公司id查询公司印章信息
        EsignCompanyDto esignCompanyAssetsA = getEsignCompany(dto.getPartyAId().intValue(), EsignCompanyTypeEnum.ASSET_COMPANY.getValue());

        //合同模板id
        List<Integer> templateIds = new ArrayList<>();
        templateIds.add(dto.getContractDedicatedId());
        templateIds.add(dto.getContractSupplementId());
        //根据id获取合同模板
        List<ContractTemplateDto> templates = getContractTemplateList(templateIds);

        //生成合同并盖章
        response = createSpecialAndSupplementContract(esignAccountB, esignCompanyAssetsA, templates, dto, uploadFileRequestDto);
        if (response.getCode() != 200) {
            return response;
        }

        long endTime = System.currentTimeMillis(); // 开始时间
        logger.info("生成专用条款和补充协议用时：》》》》》》》》" + (endTime - startTime) + "ms");
        logger.info("生成专用条款和补充协议出参：》》》》》》》》" + JSONObject.toJSONString(response));
        return response;
    }


    /**
     * 生成通用条款和保存合同
     *
     * @param esignAccountB
     * @param esignCompanyAssetsA
     * @param Templates
     * @param dto
     * @return
     */
    private ResponseResult<Boolean> createSpecialAndSupplementContract(EsignAccountDto esignAccountB,
                                                                       EsignCompanyDto esignCompanyAssetsA, List<ContractTemplateDto> Templates,
                                                                       ContractSupplementBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        ResponseResult<Boolean> response = new ResponseResult<Boolean>();
        //对象转map
        Map<String, Object> objectToMap = null;
        try {
            objectToMap = objectToMap(dto);
        } catch (Exception e) {
            response.setMessage("实体转换map异常");
            response.setCode(106);
            logger.error("实体转换map异常！！！", e);
            return response;
        }

        List<ContractDto> list = new ArrayList<>();
        List<ContractLogDto> contractLogList = new ArrayList<>();

        //获取合同路径文件夹
        String finalFilePath = getFinalFilePath();
        for (ContractTemplateDto contractTemplateDto : Templates) {
            logger.info(" 单个合同模板信息》》》》》》》》" + JSONObject.toJSONString(contractTemplateDto));
            // 获取模板信息
            byte[] templateBytes = fileEhCacheUtil.getTemplate(contractTemplateDto.getName(),
                    contractTemplateDto.getTemplatePath());

            FileCreateFromTemplateResult fileFromTemplate = createPDF(templateBytes, objectToMap, finalFilePath);
            if (fileFromTemplate == null) {
                response.setMessage("合同生成失败");
                response.setCode(106);
                logger.error("合同生成失败！！！");
                return response;
            }
            String filePath = fileFromTemplate.getDstPdfFile();// 合同路径
            SignPDFStreamBean signPDFStreamBean = new SignPDFStreamBean();
            signPDFStreamBean.setDstPdfFile(null);
            signPDFStreamBean.setStream(FileEhCacheUtil.file2byte(filePath));

            //合同盖章位置
            String[] posX = contractTemplateDto.getEsignPosX().split(",");
            String[] posY = contractTemplateDto.getEsignPosY().split(",");
            // 合同甲方盖章
            PosBean posBean = new PosBean();
            posBean.setPosPage(contractTemplateDto.getEsignPosPage());// 页码
            posBean.setPosX(Float.parseFloat(posX[0]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[0])); // 坐标
            FileDigestSignResult fileDigestSignResult = ESignLib.localSignPDFMoliSide(signPDFStreamBean, posBean,
                    esignCompanyAssetsA.getSealData(), SignType.Single);
            if (fileDigestSignResult == null) {
                logger.error("甲方盖章失败(FileDigestSignResult is null)！！！" + JSONObject.toJSONString(signPDFStreamBean) + ","
                        + JSONObject.toJSONString(posBean) + "," + SignType.Single);
                response.setCode(107);
                response.setMessage("甲方盖章失败");
                return response;
            } else if (fileDigestSignResult.getErrCode() != 0) {
                logger.error("同甲方盖章失败(" + fileDigestSignResult.getErrCode() + ":"
                        + fileDigestSignResult.getMsg() + ")" + JSONObject.toJSONString(signPDFStreamBean) + ","
                        + JSONObject.toJSONString(posBean) + "," + SignType.Single);
                response.setCode(107);
                response.setMessage("甲方盖章失败(" + fileDigestSignResult.getErrCode() + ":"
                        + fileDigestSignResult.getMsg() + ")");
                return response;
            }

            // 主合同乙方盖章
            posBean.setPosPage(contractTemplateDto.getEsignPosPage()); // 页码
            posBean.setPosX(Float.parseFloat(posX[1])); // 坐标
            posBean.setPosY(Float.parseFloat(posY[1])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFCustomerSide(fileDigestSignResult, signPDFStreamBean, posBean, esignAccountB);

            // 合同丙方盖章
            posBean.setPosPage(contractTemplateDto.getEsignPosPage());// 页码
            posBean.setPosX(Float.parseFloat(posX[2]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[2])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSide(fileDigestSignResult, signPDFStreamBean, posBean, companySealDataCacheUtil.getPartyCSealData());

            // 盖骑缝章(甲方章)
            posBean.setPosPage(contractTemplateDto.getEsignEdgesPage());// 页码
            posBean.setPosY(Float.parseFloat(contractTemplateDto.getEsignEdgesY()));
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSideEdges(fileDigestSignResult, signPDFStreamBean, posBean, esignCompanyAssetsA.getSealData());

            //盖章完成生成流
            byte[] stream = fileDigestSignResult.getStream();
            String newFileName = "molikejiht-" + UUIDUtil.getUUID() + ".pdf";
            // 上传oss
            String ossPdfUrl = null;
            try {
                ossPdfUrl = byte2FileOss(stream, finalFilePath, newFileName, uploadFileRequestDto);
                logger.info("ossPdfUrl:" + ossPdfUrl);
            } catch (Exception e) {
                logger.error("订单号为：" + dto.getOrderCode() + "合同上传oss失败！！");
                response.setCode(108);
                response.setMessage("订单号为：" + dto.getOrderCode() + "合同上传oss失败！！");
                return response;
            }

            ContractDto contractDto = getMileageBagContractDto(ossPdfUrl, dto, contractTemplateDto);
            list.add(contractDto);
            ContractLogDto contractLogDto = createContractLog(dto.getOrderCode(), dto.getBusinessType(), contractDto.getContractCode(), contractDto.getContractName(), null, true);
            contractLogList.add(contractLogDto);
            File file = new File(filePath);
            file.delete();
        }
        // 批量保存数据
        if (list != null && list.size() > 0) {
            contractService.createContractBatch(list);
        }
        // 批量保存数据
        if (contractLogList != null && contractLogList.size() > 0) {
            contractLogService.createContractLogList(contractLogList);
        }
        //提车生成补充协议和专用条款，此时要修改合同过期时间
        contractService.modifyContractEndTime(dto.getOrderCode(), dto.getEndTime());
        response.setCode(200);
        return response;
    }

    /**
     * 生成通用条款和保存合同dto
     *
     * @param ossPdfUrl
     * @param dto
     * @param contractTemplateDto
     * @return
     */
    private ContractDto getMileageBagContractDto(String ossPdfUrl, ContractSupplementBizCreateDto dto, ContractTemplateDto contractTemplateDto) {
        ContractDto contractDto = new ContractDto();
        contractDto.setContractPath(ossPdfUrl);
        if (ContractTypeEnum.SUPPLEMENT_CONTRACT.getValue() == contractTemplateDto.getTemplateType()) {
            contractDto.setContractCode(dto.getSupplementaryNumber());
        } else if (ContractTypeEnum.DEDICATED_CONTRACT.getValue() == contractTemplateDto.getTemplateType()) {
            contractDto.setContractCode(dto.getDedicateNumber());
        }
        contractDto.setOrderCode(dto.getOrderCode());
        contractDto.setContractType(contractTemplateDto.getTemplateType());
        contractDto.setContractStatus(ContractStatusEnum.EFFECTIVE.getValue());
        contractDto.setSignedTime(dto.getSignedTime());
        contractDto.setBusinessType(dto.getBusinessType());
        contractDto.setIsCreated(IsDeleteEnum.YES.getValue());
        contractDto.setContractTemplateId(contractTemplateDto.getTemplateId());
        contractDto.setContractTemplatePath(contractTemplateDto.getTemplatePath());
        contractDto.setContractName(contractTemplateDto.getName());
        contractDto.setEndTime(dto.getEndTime());
        contractDto.setEffectiveTime(dto.getEffectiveTime());
        contractDto.setIsEcontract(IsDeleteEnum.YES.getValue());
        contractDto.setGuaranteeType(dto.getIsWarrantor());
        contractDto.setPartyAId(dto.getPartyAId().intValue());
        contractDto.setPartyAName(dto.getPartyAName());
        contractDto.setPartyBId(dto.getPartyBId().intValue());
        contractDto.setPartyBName(dto.getPartyBName());
        contractDto.setPartyCName(dto.getPartyCName());
        return contractDto;
    }

    /**
     * 交车单
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public ResponseResult<Boolean> createDelivery(ContractDeliveryBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        ResponseResult<Boolean> response = createDeliveryContract(dto, uploadFileRequestDto);
        if (response.getCode() != 200) {
            Long orderCode = dto.getOrderCode();
            Integer businessType = dto.getBusinessType();
            ContractLogDto contractLogDto = createContractLog(orderCode, businessType, null, null, response.getMessage(), false);
            contractLogService.createContractLog(contractLogDto);
            DingTalkUtil.exceptionSend(ACTIVE_EXPLAIN + "订单号：" + orderCode + "生成交接单异常：" + response.getMessage());
        }
        return response;
    }

    /**
     * 交车单合同
     *
     * @param dto
     * @return
     */
    public ResponseResult<Boolean> createDeliveryContract(ContractDeliveryBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        logger.info("生成交车单 入参 》》》》》》》》" + JSON.toJSONString(dto));
        long startTime = System.currentTimeMillis();
        ParamTemplateBizCreateDto templateDto = null;
        ResponseResult<Boolean> response = new ResponseResult<Boolean>();
        try {
            //参数校验
            templateDto = validationParam(dto);
        } catch (Exception e) {
            logger.error("生成交车单 失败参数错误》》》》》》》》" + e);
            response.setData(false);
            response.setCode(400);
            response.setMessage("参数错误：" + e.getMessage());
            return response;
        }
        //合同集合
        List<ContractDto> contractDtoList = new ArrayList<>();
        //业务类型判断
        List<ContractTemplateDto> templates = businessTypeJudge(dto, contractDtoList);
        logger.info("生成交车单，查询主合同编号" + JSONObject.toJSONString(contractDtoList));
        if (contractDtoList == null || contractDtoList.size() == 0) {
            logger.error("生成交车单失败！！！,没有主合同编号");
            response.setCode(500);
            response.setData(false);
            response.setMessage("生成交车单失败！！！,没有主合同编号");
            return response;
        }
        @SuppressWarnings("unused")
        ContractTemplateDto contractTemplateDto = templates.get(0);
        // 模板文件路径
        String templatePath = contractTemplateDto.getTemplatePath();
        // 获取合同路径文件夹
        String finalFilePath = getFinalFilePath();
        // 生成的文件路径
        String targetPath = getFinalName(finalFilePath, templatePath);
        // 图片路径
        String imagePath = getFinalName(finalFilePath, dto.getCarUrl());
        //下载图片
        logger.info("生成交车单下载图片开始》》》》》》》》start");
        response = downloadPicture(response, dto.getCarUrl(), imagePath);
        logger.info("生成交车单下载图片结束》》》》》》》》end");
        if (!response.getData()) {
            return response;
        }
        //PDF中插入图片
        logger.info("PDF中插入图片开始》》》》》》》》start");
        response = pdfAddImage(response, templatePath, targetPath, imagePath);
        logger.info("PDF中插入图片结束》》》》》》》》end");
        if (!response.getData()) {
            return response;
        }
        logger.info("获取合同模板 开始》》》》》》》》start");
        response = getTemplate(response, templateDto, targetPath, contractTemplateDto, dto, finalFilePath, contractDtoList, uploadFileRequestDto);
        logger.info("获取合同模板 结束》》》》》》》》end");
        if (!response.getData()) {
            return response;
        }

        //里程包
        if (dto.getBusinessType().equals(ContractBusinessTypeEnum.SUBSCRIBE.getValue())) {
            Integer handoverType = dto.getHandoverType();
            //如果是还车则需要修改合同状态
            if (handoverType != null && OrderHandoverTypeEnum.TRANSFER_VEHICLE.getValue() == handoverType) {
                if (dto.getMainOrderCode() != null) {
                    mpdifyContractStatus(dto.getMainOrderCode(), ContractStatusEnum.EXPIRE_NONEFFECTIVE.getValue());
                    modifyStatusByMainOrderCode(dto.getMainOrderCode(), ContractStatusEnum.EXPIRE_NONEFFECTIVE.getValue());
                } else {
                    mpdifyContractStatus(dto.getOrderCode(), ContractStatusEnum.EXPIRE_NONEFFECTIVE.getValue());
                }
            } else if (handoverType != null && OrderHandoverTypeEnum.DELIVERY_OF_VEHICLE.getValue() == handoverType) {
                //提车此时要修改合同过期时间
                contractService.modifyContractEndTime(dto.getOrderCode(), dto.getEndTime());
            }
        }
        long endTime = System.currentTimeMillis();
        logger.info("生成交车单 出参耗时 》》》》》》》》" + (endTime - startTime) + "ms");
        logger.info("生成交车单 出参 》》》》》》》》" + JSONObject.toJSONString(response));
        return response;
    }

    /**
     * 获取合同模板
     *
     * @param response
     * @param templateDto
     * @return
     */
    private ResponseResult<Boolean> getTemplate(ResponseResult<Boolean> response, ParamTemplateBizCreateDto templateDto,
                                                String targetPath, ContractTemplateDto contractTemplateDto,
                                                ContractDeliveryBizCreateDto dto, String finalFilePath, List<ContractDto> contractDtoList,
                                                UploadFileRequestDto uploadFileRequestDto) {
        // 获取模板信息
        byte[] templateBytes = FileEhCacheUtil.file2byte(targetPath);
        Map<String, Object> objectToMap = null;
        try {
            objectToMap = objectToMap(templateDto);
        } catch (Exception e) {
            logger.error("Bean 转 Map 异常 》》》》》》》》", e);
            response.setMessage("Bean 转 Map 异常" + e.getMessage());
            response.setCode(500);
            response.setData(false);
            return response;
        }
        FileCreateFromTemplateResult fileFromTemplate = createPDF(templateBytes, objectToMap, finalFilePath);
        //删除目标文件
        File targetPathFile = new File(targetPath);
        targetPathFile.delete();

        if (fileFromTemplate == null) {
            response.setMessage("交车单生成失败");
            response.setCode(500);
            response.setData(false);
            logger.error("获取合同模板   》》》》》》》》交车单生成失败");
            return response;
        }

        //查询用户印章信息
        EsignAccountDto esignAccountDto = getEsignAccount(dto.getPartyBName(), dto.getPartyBCard());

        // 合同路径
        String filePath = fileFromTemplate.getDstPdfFile();
        SignPDFStreamBean signPDFStreamBean = new SignPDFStreamBean();
        signPDFStreamBean.setDstPdfFile(null);
        signPDFStreamBean.setStream(FileEhCacheUtil.file2byte(filePath));

        String[] posX = contractTemplateDto.getEsignPosX().split(",");
        String[] posY = contractTemplateDto.getEsignPosY().split(",");
        // 交车单乙方盖章
        PosBean posBean = new PosBean();
        posBean.setPosPage(contractTemplateDto.getEsignPosPage()); // 页码
        posBean.setPosX(Float.parseFloat(posX[0])); // 坐标
        posBean.setPosY(Float.parseFloat(posY[0])); // 坐标
        FileDigestSignResult fileDigestSignResult = ESignLib.localSignPDFCustomerSide(esignAccountDto.getAccountId(),
                esignAccountDto.getSealData(), signPDFStreamBean, posBean, SignType.Single);
        if (fileDigestSignResult == null) {
            logger.error("承租人盖章失败！！！" + esignAccountDto.getAccountId() + ","
                    + JSONObject.toJSONString(signPDFStreamBean) + ","
                    + JSONObject.toJSONString(posBean) + "," + SignType.Single);
            response.setCode(500);
            response.setData(false);
            response.setMessage("承租人盖章失败！！！");
            return response;
        } else if (fileDigestSignResult.getErrCode() != 0) {
            logger.error("承租人盖章失败！！！" + esignAccountDto.getAccountId() + ","
                    + JSONObject.toJSONString(signPDFStreamBean) + ","
                    + JSONObject.toJSONString(posBean) + "," + SignType.Single);
            response.setCode(500);
            response.setData(false);
            response.setMessage("承租人盖章失败！！！");
            return response;
        }
        //合同完成
        byte[] stream = fileDigestSignResult.getStream();
        // 文件名称
        String newFileName = "molikejiht-" + UUIDUtil.getUUID() + ".pdf";
        // 上传oss
        String ossPdfUrl = "";
        try {
            ossPdfUrl = byte2FileOss(stream, finalFilePath, newFileName, uploadFileRequestDto);
        } catch (Exception e) {
            logger.error("交车单上传oss失败", e);
            response.setCode(500);
            response.setData(false);
            response.setMessage("交车单上传oss失败");
            return response;
        }
        //保存交车单信息
        response = saveEsignLog(response, ossPdfUrl, dto, esignAccountDto, contractDtoList, contractTemplateDto);
        if (!response.getData()) {
            return response;
        }
        //删除合同路径
        File file = new File(filePath);
        file.delete();
        return response;
    }


    /**
     * 保存交车单信息
     *
     * @param response
     * @param ossPdfUrl
     * @param dto
     * @param esignAccountDto
     * @param contractDtoList
     * @param contractTemplateDto
     * @return
     */
    private ResponseResult<Boolean> saveEsignLog(ResponseResult<Boolean> response, String ossPdfUrl,
                                                 ContractDeliveryBizCreateDto dto, EsignAccountDto esignAccountDto,
                                                 List<ContractDto> contractDtoList, ContractTemplateDto contractTemplateDto) {
        ContractDto contractDto = new ContractDto();
        contractDto.setContractPath(ossPdfUrl);
        contractDto.setContractCode(contractDtoList.get(0).getContractCode() + "(1)"); // 合同编号
        Integer handoverType = dto.getHandoverType();
        if (ContractBusinessTypeEnum.EXCLUSIVEL.getValue() == dto.getBusinessType()) {
            if (handoverType != null && OrderHandoverTypeEnum.DELIVERY_OF_VEHICLE.getValue() == handoverType) {
                contractDto.setContractType(ContractTypeEnum.CAR_CONTRACT.getValue());
            } else if (handoverType != null && OrderHandoverTypeEnum.TRANSFER_VEHICLE.getValue() == handoverType) {
                contractDto.setContractType(ContractTypeEnum.DEDICATED_RETURN_CAR.getValue());
                contractDto.setContractCode(contractDtoList.get(0).getContractCode() + "(2)"); // 合同编号
            }
        } else if (ContractBusinessTypeEnum.SUBSCRIBE.getValue() == dto.getBusinessType()) {
            if (handoverType != null && OrderHandoverTypeEnum.DELIVERY_OF_VEHICLE.getValue() == handoverType) {
                contractDto.setContractType(ContractTypeEnum.MILEAGE_BAG_CAR_CONTRACT.getValue());
            } else if (handoverType != null && OrderHandoverTypeEnum.TRANSFER_VEHICLE.getValue() == handoverType) {
                contractDto.setContractType(ContractTypeEnum.MILEAGE_BAG_RETURN_CAR.getValue());
                contractDto.setContractCode(contractDtoList.get(0).getContractCode() + "(2)"); // 合同编号
            } else if (handoverType != null && OrderHandoverTypeEnum.SURVEY_REPORT_VEHICLE.getValue() == handoverType) {
                contractDto.setContractType(ContractTypeEnum.MILEAGE_BAG_VALIDATE_CONTRACT.getValue());
                contractDto.setContractCode(contractDtoList.get(0).getContractCode() + "(3)"); // 合同编号
            }
        }

        contractDto.setOrderCode(dto.getOrderCode());
        contractDto.setGuaranteeType(dto.getIsWarrantor());
        contractDto.setContractStatus(ContractStatusEnum.EFFECTIVE.getValue());
        contractDto.setSignedTime(dto.getSignedTime());
        contractDto.setBusinessType(dto.getBusinessType());
        contractDto.setMainOrderCode(dto.getMainOrderCode());
        contractDto.setIsCreated(IsDeleteEnum.YES.getValue());
        contractDto.setContractTemplateId(contractTemplateDto.getTemplateId());
        contractDto.setContractTemplatePath(contractTemplateDto.getTemplatePath());
        contractDto.setContractName(contractTemplateDto.getName());
        contractDto.setEndTime(dto.getEndTime());
        contractDto.setEffectiveTime(dto.getEffectiveTime());
        contractDto.setIsEcontract(IsDeleteEnum.YES.getValue());
        contractDto.setPartyAId(dto.getPartyAId().intValue());
        contractDto.setPartyAName(dto.getPartyAName());
        contractDto.setPartyBId(dto.getPartyBId().intValue());
        contractDto.setPartyBName(dto.getPartyBName());
        contractDto.setPartyCId(dto.getPartyCId().intValue());
        contractDto.setPartyCName(dto.getPartyCName());

        List<ContractDto> list = new ArrayList<ContractDto>(1);
        List<ContractLogDto> contractLogList = new ArrayList<>();
        list.add(contractDto);
        ContractLogDto contractLogDto = createContractLog(dto.getOrderCode(), dto.getBusinessType(), contractDto.getContractCode(), contractDto.getContractName(), null, true);
        contractLogList.add(contractLogDto);
        // 批量保存数据
        if (list != null && list.size() > 0) {
            contractService.createContractBatch(list);
        }

        // 批量保存数据
        if (contractLogList != null && contractLogList.size() > 0) {
            contractLogService.createContractLogList(contractLogList);
        }
        response.setCode(200);
        response.setData(true);
        return response;
    }

    /**
     * 生成里程包合同
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public ResponseResult<String> createMileageBag(ContractMileageBagBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        ResponseResult<String> response = createMileageBagContract(dto, uploadFileRequestDto);
        if (response.getCode() != 200) {
            Long orderCode = dto.getOrderCode();
            Integer businessType = dto.getBusinessType();
            ContractLogDto contractLogDto = createContractLog(orderCode, businessType, null, null, response.getMessage(), false);
            contractLogService.createContractLog(contractLogDto);
            DingTalkUtil.exceptionSend(ACTIVE_EXPLAIN + "订单号：" + orderCode + "生成订阅里程服务合同异常：" + response.getMessage());
        }
        return response;
    }


    /**
     * 创建合同
     *
     * @param dto
     * @return
     */
    private ResponseResult<String> createMileageBagContract(ContractMileageBagBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        ResponseResult<String> response = new ResponseResult<String>();
        long startTime = System.currentTimeMillis(); // 开始时间
        logger.info("生成里程包合同合同入参：》》》》》》》》" + JSONObject.toJSONString(dto));
        getContractIsExist(dto.getOrderCode(), ContractTypeEnum.MILEAGE_BAG_CONTRACT.getValue());
        //用户印章信息
        EsignAccountDto esignAccountB = getEsignAccount(dto.getPartyBName(), dto.getPartyBCard());
        //根据甲方1公司id查询公司印章信息
        EsignCompanyDto esignCompanyAssetsO = getEsignCompany(dto.getPartyAOId().intValue(), EsignCompanyTypeEnum.ASSET_COMPANY.getValue());
        //根据丙方公司id查询公司印章信息
        EsignDealerDto esignDealerAssets = getEsignDealer(dto.getPartyCId().intValue());

        List<Integer> templateIds = new ArrayList<>();
        templateIds.add(dto.getContractMasterId());
        //根据id获取合同模板
        List<ContractTemplateDto> templates = getContractTemplateList(templateIds);
        //获取合同编号
        String contractNumber = getContractNumber(PREFIX, dto.getBrandChannel());
        dto.setContractNumber(contractNumber);
        //生成合同并盖章
        response = createMileageBagContract(esignAccountB, esignCompanyAssetsO, esignDealerAssets, templates, dto, uploadFileRequestDto);
        if (response.getCode() != 200) {
            return response;
        }

        long endTime = System.currentTimeMillis(); //结束时间
        logger.info("生成通用条款和保证合同用时：》》》》》》》》" + (endTime - startTime) + "ms");
        logger.info("生成通用条款和保证合同出参：》》》》》》》》" + JSONObject.toJSONString(response));
        return response;
    }

    /**
     * 生成里程包合同
     *
     * @param esignAccountB
     * @param Templates
     * @param dto
     * @return
     */
    private ResponseResult<String> createMileageBagContract(EsignAccountDto esignAccountB, EsignCompanyDto esignCompanyAssetsO,
                                                            EsignDealerDto esignDealerAssets, List<ContractTemplateDto> Templates,
                                                            ContractMileageBagBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        ResponseResult<String> response = new ResponseResult<String>();
        // 对象转map
        Map<String, Object> objectToMap;
        try {
            objectToMap = objectToMap(dto);
        } catch (Exception e) {
            response.setMessage("实体转换map异常");
            response.setCode(106);
            logger.error("实体转换map异常！！！", e);
            return response;
        }

        List<ContractDto> list = new ArrayList<>();
        List<ContractLogDto> contractLogList = new ArrayList<>();
        // 获取合同路径文件夹
        String finalFilePath = getFinalFilePath();
        for (ContractTemplateDto contractTemplateDto : Templates) {
            logger.info(" 单个合同模板信息》》》》》》》》" + JSONObject.toJSONString(contractTemplateDto));
            // 获取模板信息
            byte[] templateBytes = fileEhCacheUtil.getTemplate(contractTemplateDto.getName(),
                    contractTemplateDto.getTemplatePath());

            FileCreateFromTemplateResult fileFromTemplate = createPDF(templateBytes, objectToMap, finalFilePath);
            if (fileFromTemplate == null) {
                response.setMessage("合同生成失败");
                response.setCode(106);
                logger.error("合同生成失败！！！");
                return response;
            }
            String filePath = fileFromTemplate.getDstPdfFile();// 合同路径
            SignPDFStreamBean signPDFStreamBean = new SignPDFStreamBean();
            signPDFStreamBean.setDstPdfFile(null);
            signPDFStreamBean.setStream(FileEhCacheUtil.file2byte(filePath));

            // 合同盖章页
            String[] esignPosPage = contractTemplateDto.getEsignPosPage().split(",");
            // 合同盖章位置
            String[] posX = contractTemplateDto.getEsignPosX().split(",");
            String[] posY = contractTemplateDto.getEsignPosY().split(",");
            // 合同甲方1盖章
            PosBean posBean = new PosBean();
            posBean.setPosPage(esignPosPage[0]);// 页码
            posBean.setPosX(Float.parseFloat(posX[0]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[0])); // 坐标
            FileDigestSignResult fileDigestSignResult = ESignLib.localSignPDFMoliSide(signPDFStreamBean, posBean,
                    esignCompanyAssetsO.getSealData(), SignType.Single);
            if (fileDigestSignResult == null) {
                logger.error("甲方盖章失败(FileDigestSignResult is null)！！！" + JSONObject.toJSONString(signPDFStreamBean) + ","
                        + JSONObject.toJSONString(posBean) + "," + SignType.Single);
                response.setCode(107);
                response.setMessage("甲方盖章失败");
                return response;
            } else if (fileDigestSignResult.getErrCode() != 0) {
                logger.error(
                        "同甲方盖章失败(" + fileDigestSignResult.getErrCode() + ":" + fileDigestSignResult.getMsg() + ")"
                                + JSONObject.toJSONString(signPDFStreamBean) + ","
                                + JSONObject.toJSONString(posBean) + "," + SignType.Single);
                response.setCode(107);
                response.setMessage(
                        "甲方盖章失败(" + fileDigestSignResult.getErrCode() + ":" + fileDigestSignResult.getMsg() + ")");
                return response;
            }

            // 合同甲方2盖章
            posBean.setPosPage(esignPosPage[0]);// 页码
            posBean.setPosX(Float.parseFloat(posX[1]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[1])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSide(fileDigestSignResult, signPDFStreamBean, posBean,
                    companySealDataCacheUtil.getPartyCSealData());

            // 主合同乙方盖章
            posBean.setPosPage(esignPosPage[0]); // 页码
            posBean.setPosX(Float.parseFloat(posX[2])); // 坐标
            posBean.setPosY(Float.parseFloat(posY[2])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFCustomerSide(fileDigestSignResult, signPDFStreamBean, posBean,
                    esignAccountB);

            // 合同丙方盖章
            posBean.setPosPage(esignPosPage[0]);// 页码
            posBean.setPosX(Float.parseFloat(posX[3]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[3])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSide(fileDigestSignResult, signPDFStreamBean, posBean,
                    esignDealerAssets.getSealData());

            // 订阅服务订单合同甲方1盖章
            posBean.setPosPage(esignPosPage[1]);// 页码
            posBean.setPosX(Float.parseFloat(posX[4]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[4])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSide(fileDigestSignResult, signPDFStreamBean, posBean,
                    esignCompanyAssetsO.getSealData());

            // 订阅服务订单合同甲方2盖章
            posBean.setPosPage(esignPosPage[1]);// 页码
            posBean.setPosX(Float.parseFloat(posX[5]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[5])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSide(fileDigestSignResult, signPDFStreamBean, posBean,
                    companySealDataCacheUtil.getPartyCSealData());


            // 订阅服务订单合同乙方盖章
            posBean.setPosPage(esignPosPage[1]); // 页码
            posBean.setPosX(Float.parseFloat(posX[6])); // 坐标
            posBean.setPosY(Float.parseFloat(posY[6])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFCustomerSide(fileDigestSignResult, signPDFStreamBean, posBean,
                    esignAccountB);

            // 订阅服务订单合同丙方盖章
            posBean.setPosPage(esignPosPage[1]);// 页码
            posBean.setPosX(Float.parseFloat(posX[7]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[7])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSide(fileDigestSignResult, signPDFStreamBean, posBean,
                    esignCompanyAssetsO.getSealData());


            // 盖骑缝章(甲方2章)
            posBean.setPosPage(contractTemplateDto.getEsignEdgesPage());// 页码
            posBean.setPosY(Float.parseFloat(contractTemplateDto.getEsignEdgesY()));
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSideEdges(fileDigestSignResult, signPDFStreamBean, posBean,
                    companySealDataCacheUtil.getPartyCSealData());

            // 盖章完成生成流
            byte[] stream = fileDigestSignResult.getStream();
            String newFileName = "molikejiht-" + UUIDUtil.getUUID() + ".pdf";
            // 上传oss
            String ossPdfUrl = null;
            try {
                ossPdfUrl = byte2FileOss(stream, finalFilePath, newFileName, uploadFileRequestDto);
                logger.info("ossPdfUrl:" + ossPdfUrl);
            } catch (Exception e) {
                logger.error("订单号为：" + dto.getOrderCode() + "合同上传oss失败！！");
                response.setCode(108);
                response.setMessage("订单号为：" + dto.getOrderCode() + "合同上传oss失败！！");
                return response;
            }

            ContractDto contractDto = getMileageBagContractDto(ossPdfUrl, dto, contractTemplateDto);
            list.add(contractDto);
            ContractLogDto contractLogDto = createContractLog(dto.getOrderCode(), dto.getBusinessType(), contractDto.getContractCode(), contractDto.getContractName(), null, true);
            contractLogList.add(contractLogDto);
            File file = new File(filePath);
            file.delete();
        }

        // 批量保存数据
        if (list != null && list.size() > 0) {
            contractService.createContractBatch(list);
        }

        // 批量保存数据
        if (contractLogList != null && contractLogList.size() > 0) {
            contractLogService.createContractLogList(contractLogList);
        }

        response.setCode(200);
        response.setData(dto.getContractNumber());
        return response;
    }

    /**
     * 加购里程 和 续单里程  合同
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public ResponseResult<String> createPurchased(ContractMileagePurchasedBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        ResponseResult<String> response = createPurchasedContract(dto, uploadFileRequestDto);
        if (response.getCode() != 200) {
            Long orderCode = dto.getOrderCode();
            Integer businessType = dto.getBusinessType();
            ContractLogDto contractLogDto = createContractLog(orderCode, businessType, null, null, response.getMessage(), false);
            contractLogService.createContractLog(contractLogDto);
            Integer contractType = dto.getContractType();
            String contractName = "";
            if (ContractTypeEnum.MILEAGE_BAG_RENEW_CONTRACT.getValue() == contractType) {
                contractName = "续订合同";
            } else if (ContractTypeEnum.MILEAGE_BAG_PURCHASED_CONTRACT.getValue() == contractType) {
                contractName = "加购合同";
            }

            DingTalkUtil.exceptionSend(ACTIVE_EXPLAIN + "订单号：" + orderCode + "生成" + contractName + "异常：" + response.getMessage());
        }
        return response;
    }


    /**
     * 加购里程 和 续单里程  合同
     *
     * @param dto
     * @return
     */
    public ResponseResult<String> createPurchasedContract(ContractMileagePurchasedBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        long startTime = System.currentTimeMillis(); // 开始时间
        logger.info("生成里程包合同合同入参：》》》》》》》》" + JSONObject.toJSONString(dto));

        ResponseResult<String> response = new ResponseResult<String>();

        //根据用户身份证号和姓名查询该用户的印章信息
        EsignAccountDto esignAccountB = getEsignAccount(dto.getPartyBName(), dto.getPartyBCard());
        //根据甲方1公司id查询公司印章信息
        EsignCompanyDto esignCompanyAssetsO = getEsignCompany(dto.getPartyAOId().intValue(), EsignCompanyTypeEnum.ASSET_COMPANY.getValue());
        //根据丙方公司id查询公司印章信息
        EsignDealerDto esignDealerAssets = getEsignDealer(dto.getPartyCId().intValue());
        //根据模板类型获取合同模板
        List<ContractTemplateDto> templateList = getContractTemplates(dto.getContractType());

        //获取第一笔订单编号
        String contractCode = getContractCode(dto.getMainOrderCode(), dto.getOrderCode(), ContractTypeEnum.MILEAGE_BAG_CONTRACT.getValue());

        //生成合同并盖章
        response = createPurchasedContract(esignAccountB, esignCompanyAssetsO, esignDealerAssets, templateList, dto, contractCode, uploadFileRequestDto);
        if (response.getCode() != 200) {
            return response;
        }

        long endTime = System.currentTimeMillis(); //结束时间
        logger.info("生成通用条款和保证合同用时：》》》》》》》》" + (endTime - startTime) + "ms");
        logger.info("生成通用条款和保证合同出参：》》》》》》》》" + JSONObject.toJSONString(response));
        return response;
    }


    /**
     * 加购里程 和 续单里程  合同
     *
     * @param esignAccountB
     * @param esignCompanyAssetsO
     * @param esignStoreAssets
     * @param templates
     * @param dto
     * @param contractCode
     * @return
     */
    private ResponseResult<String> createPurchasedContract(EsignAccountDto esignAccountB, EsignCompanyDto esignCompanyAssetsO,
                                                           EsignDealerDto esignStoreAssets, List<ContractTemplateDto> templates,
                                                           ContractMileagePurchasedBizCreateDto dto, String contractCode,
                                                           UploadFileRequestDto uploadFileRequestDto) {
        ResponseResult<String> response = new ResponseResult<String>();
        // 对象转map
        Map<String, Object> objectToMap;
        try {
            objectToMap = objectToMap(dto);
        } catch (Exception e) {
            response.setMessage("实体转换map异常");
            response.setCode(106);
            logger.error("实体转换map异常！！！", e);
            return response;
        }

        List<ContractDto> list = new ArrayList<>();
        List<ContractLogDto> contractLogList = new ArrayList<>();
        String finalFilePath = getFinalFilePath();
        for (ContractTemplateDto contractTemplateDto : templates) {
            logger.info(" 单个合同模板信息》》》》》》》》" + JSONObject.toJSONString(contractTemplateDto));
            // 获取模板信息
            byte[] templateBytes = fileEhCacheUtil.getTemplate(contractTemplateDto.getName(),
                    contractTemplateDto.getTemplatePath());

            FileCreateFromTemplateResult fileFromTemplate = createPDF(templateBytes, objectToMap, finalFilePath);
            if (fileFromTemplate == null) {
                response.setMessage("合同生成失败");
                response.setCode(106);
                logger.error("合同生成失败！！！");
                return response;
            }
            String filePath = fileFromTemplate.getDstPdfFile();// 合同路径
            SignPDFStreamBean signPDFStreamBean = new SignPDFStreamBean();
            signPDFStreamBean.setDstPdfFile(null);
            signPDFStreamBean.setStream(FileEhCacheUtil.file2byte(filePath));

            // 合同盖章页
            String esignPosPage = contractTemplateDto.getEsignPosPage();
            // 合同盖章位置
            String[] posX = contractTemplateDto.getEsignPosX().split(",");
            String[] posY = contractTemplateDto.getEsignPosY().split(",");
            // 合同甲方1盖章
            PosBean posBean = new PosBean();
            posBean.setPosPage(esignPosPage);// 页码
            posBean.setPosX(Float.parseFloat(posX[0]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[0])); // 坐标
            FileDigestSignResult fileDigestSignResult = ESignLib.localSignPDFMoliSide(signPDFStreamBean, posBean,
                    esignCompanyAssetsO.getSealData(), SignType.Single);
            if (fileDigestSignResult == null) {
                logger.error("甲方盖章失败(FileDigestSignResult is null)！！！" + JSONObject.toJSONString(signPDFStreamBean) + ","
                        + JSONObject.toJSONString(posBean) + "," + SignType.Single);
                response.setCode(107);
                response.setMessage("甲方盖章失败");
                return response;
            } else if (fileDigestSignResult.getErrCode() != 0) {
                logger.error(
                        "同甲方盖章失败(" + fileDigestSignResult.getErrCode() + ":" + fileDigestSignResult.getMsg() + ")"
                                + JSONObject.toJSONString(signPDFStreamBean) + ","
                                + JSONObject.toJSONString(posBean) + "," + SignType.Single);
                response.setCode(107);
                response.setMessage(
                        "甲方盖章失败(" + fileDigestSignResult.getErrCode() + ":" + fileDigestSignResult.getMsg() + ")");
                return response;
            }

            // 订阅服务订单合同甲方1盖章
            posBean.setPosPage(esignPosPage);// 页码
            posBean.setPosX(Float.parseFloat(posX[0]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[0])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSide(fileDigestSignResult, signPDFStreamBean, posBean,
                    esignCompanyAssetsO.getSealData());

            // 订阅服务订单合同甲方2盖章
            posBean.setPosPage(esignPosPage);// 页码
            posBean.setPosX(Float.parseFloat(posX[1]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[1])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSide(fileDigestSignResult, signPDFStreamBean, posBean,
                    companySealDataCacheUtil.getPartyCSealData());


            // 订阅服务订单合同乙方盖章
            posBean.setPosPage(esignPosPage); // 页码
            posBean.setPosX(Float.parseFloat(posX[2])); // 坐标
            posBean.setPosY(Float.parseFloat(posY[2])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFCustomerSide(fileDigestSignResult, signPDFStreamBean, posBean,
                    esignAccountB);

            // 订阅服务订单合同丙方盖章
            posBean.setPosPage(esignPosPage);// 页码
            posBean.setPosX(Float.parseFloat(posX[3]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[3])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSide(fileDigestSignResult, signPDFStreamBean, posBean,
                    esignStoreAssets.getSealData());


            // 盖骑缝章(甲方2章)
            posBean.setPosPage(contractTemplateDto.getEsignEdgesPage());// 页码
            posBean.setPosY(Float.parseFloat(contractTemplateDto.getEsignEdgesY()));
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSideEdges(fileDigestSignResult, signPDFStreamBean, posBean,
                    companySealDataCacheUtil.getPartyCSealData());

            // 盖章完成生成流
            byte[] stream = fileDigestSignResult.getStream();
            String newFileName = "molikejiht-" + UUIDUtil.getUUID() + ".pdf";
            // 上传oss
            String ossPdfUrl = null;
            try {
                ossPdfUrl = byte2FileOss(stream, finalFilePath, newFileName, uploadFileRequestDto);
                logger.info("ossPdfUrl:" + ossPdfUrl);
            } catch (Exception e) {
                logger.error("订单号为：" + dto.getOrderCode() + "合同上传oss失败！！");
                response.setCode(108);
                response.setMessage("订单号为：" + dto.getOrderCode() + "合同上传oss失败！！");
                return response;
            }
            ContractDto contractDto = getPurchasedContractDto(ossPdfUrl, dto, contractTemplateDto, contractCode);
            list.add(contractDto);
            ContractLogDto contractLogDto = createContractLog(dto.getOrderCode(), dto.getBusinessType(), contractDto.getContractCode(), contractDto.getContractName(), null, true);
            contractLogList.add(contractLogDto);
            File file = new File(filePath);
            file.delete();
        }

        // 批量保存数据
        if (list != null && list.size() > 0) {
            contractService.createContractBatch(list);
        }
        //里程包续订 则修改主合同过期时间
        if (ContractTypeEnum.MILEAGE_BAG_RENEW_CONTRACT.getValue() == dto.getContractType()) {
            contractService.modifyContractEndTime(dto.getMainOrderCode(), dto.getEndTime());
        }
        // 批量保存数据
        if (contractLogList != null && contractLogList.size() > 0) {
            contractLogService.createContractLogList(contractLogList);
        }
        response.setCode(200);
        response.setData(contractCode);
        return response;
    }

    /**
     * 加购里程 和 续单里程  合同
     *
     * @param ossPdfUrl
     * @param dto
     * @param contractTemplateDto
     * @param contractCode
     * @return
     */
    private ContractDto getPurchasedContractDto(String ossPdfUrl, ContractMileagePurchasedBizCreateDto dto,
                                                ContractTemplateDto contractTemplateDto, String contractCode) {
        ContractDto contractDto = new ContractDto();
        contractDto.setContractPath(ossPdfUrl);
        contractDto.setContractCode(contractCode); // 合同编号
        contractDto.setOrderCode(dto.getOrderCode());
        contractDto.setMainOrderCode(dto.getMainOrderCode());
        contractDto.setContractType(contractTemplateDto.getTemplateType());
        contractDto.setContractStatus(ContractStatusEnum.EFFECTIVE.getValue());
        contractDto.setSignedTime(dto.getSignedTime());
        contractDto.setBusinessType(dto.getBusinessType());
        contractDto.setIsCreated(IsDeleteEnum.YES.getValue());
        contractDto.setContractTemplateId(contractTemplateDto.getTemplateId());
        contractDto.setContractTemplatePath(contractTemplateDto.getTemplatePath());
        contractDto.setContractName(contractTemplateDto.getName());
        contractDto.setEndTime(dto.getEndTime());
        contractDto.setEffectiveTime(dto.getEffectiveTime());
        contractDto.setIsEcontract(IsDeleteEnum.YES.getValue());
        contractDto.setGuaranteeType(0);
        contractDto.setPartyAId(dto.getPartyAOId().intValue());
        contractDto.setPartyAName(dto.getPartyAOName());
        contractDto.setPartyBId(dto.getPartyBId().intValue());
        contractDto.setPartyBName(dto.getPartyBName());
        contractDto.setPartyCId(dto.getPartyCId().intValue());
        contractDto.setPartyCName(dto.getPartyCName());
        return contractDto;
    }


    /**
     * 创建合同dto
     *
     * @param ossPdfUrl
     * @param dto
     * @param contractTemplateDto
     * @return
     */
    private ContractDto getMileageBagContractDto(String ossPdfUrl, ContractMileageBagBizCreateDto dto, ContractTemplateDto contractTemplateDto) {
        ContractDto contractDto = new ContractDto();
        contractDto.setContractPath(ossPdfUrl);
        contractDto.setContractCode(dto.getContractNumber()); // 合同编号
        contractDto.setOrderCode(dto.getOrderCode());
        contractDto.setContractType(contractTemplateDto.getTemplateType());
        contractDto.setContractStatus(ContractStatusEnum.EFFECTIVE.getValue());
        contractDto.setSignedTime(dto.getSignedTime());
        contractDto.setBusinessType(dto.getBusinessType());
        contractDto.setIsCreated(IsDeleteEnum.YES.getValue());
        contractDto.setContractTemplateId(contractTemplateDto.getTemplateId());
        contractDto.setContractTemplatePath(contractTemplateDto.getTemplatePath());
        contractDto.setContractName(contractTemplateDto.getName());
        contractDto.setEndTime(dto.getEndTime());
        contractDto.setEffectiveTime(dto.getEffectiveTime());
        contractDto.setIsEcontract(IsDeleteEnum.YES.getValue());
        contractDto.setGuaranteeType(0);
        contractDto.setPartyAId(dto.getPartyAOId().intValue());
        contractDto.setPartyAName(dto.getPartyAOName());
        contractDto.setPartyBId(dto.getPartyBId().intValue());
        contractDto.setPartyBName(dto.getPartyBName());
        contractDto.setPartyCId(dto.getPartyCId().intValue());
        contractDto.setPartyCName(dto.getPartyCName());
        return contractDto;
    }


    /**
     * 创建合同日志
     *
     * @param orderCode
     * @param businessType
     * @param contractCode
     * @param contractName
     * @param failureReason
     * @param isCreated
     * @return
     */
    private ContractLogDto createContractLog(Long orderCode, Integer businessType, String contractCode, String contractName,
                                             String failureReason, Boolean isCreated) {
        ContractLogDto contractLogDto = new ContractLogDto();
        contractLogDto.setBusinessType(businessType.byteValue());
        contractLogDto.setContractCode(contractCode);
        contractLogDto.setContractName(contractName);
        contractLogDto.setFailureReason(failureReason);
        contractLogDto.setOrderCode(orderCode);
        contractLogDto.setIsCreated(isCreated);
        return contractLogDto;
    }

    /**
     * 合同是否存在
     *
     * @param dto
     * @throws Exception
     */
    private void checkContractIsExist(ContractGeneralBizCreateDto dto) {
        Long orderCode = dto.getOrderCode();
        Integer contractMasterId = dto.getContractMasterId();

        if (contractMasterId != null) {
            getContractIsExist(orderCode, ContractTypeEnum.COMMON_CONTRACT.getValue());
        }
    }

    /**
     * 获取模板
     *
     * @param dto
     * @return
     */
    private List<Integer> getTemplateList(ContractGeneralBizCreateDto dto) {
        //合同模板id
        List<Integer> templateIds = new ArrayList<>();
        templateIds.add(dto.getContractMasterId());

        if (dto.getIsWarrantor() == 1) {
            templateIds.add(dto.getContractGuaranteeId());
        }
        return templateIds;
    }

    /**
     * 获取合同编号
     *
     * @param dto
     */
    private void getContractNumber(ContractGeneralBizCreateDto dto) {
        String contractNumber = getContractNumber(null, dto.getBrandChannel());
        dto.setContractNumber(contractNumber);
        //保证合同
        dto.setGuaranteeNumber(contractNumber + "-3");
        //专用条款
        dto.setDedicateNumber(contractNumber + "-1");
    }

    /**
     * 合同是否生成
     *
     * @param orderCode
     * @param contractType
     * @throws Exception
     */
    private void getContractIsExist(Long orderCode, Integer contractType) {
        List<ContractDto> contractList = contractService.getContractListByOrderCode(orderCode, contractType);
        if (contractList != null && contractList.size() > 0) {
            throw new BizException(104, "合同已经生成！！！");
        }
    }

    /**
     * 承租人印章信息
     *
     * @param name
     * @param idNumber
     * @return
     */
    private EsignAccountDto getEsignAccount(String name, String idNumber) {
        EsignAccountDto esignAccountDto = esignAccountService.getEsignByNameAndIdNumber(name, idNumber);
        if (esignAccountDto == null) {
            logger.error("该承租人没有生成印章信息(" + name + ":" + idNumber + ")");
            throw new BizException(101, "该承租人没有生成印章信息");
        }
        return esignAccountDto;
    }

    /**
     * 公司印章信息
     *
     * @param partyId
     * @param type
     * @return
     */
    private EsignCompanyDto getEsignCompany(Integer partyId, Integer type) {
        EsignCompanyDto esignCompanyDto = esignCompanyService.getEsignCompanyByCompanyId(partyId, type);
        if (esignCompanyDto == null) {
            throw new BizException(101, "该公司没有生成印章信息");
        }
        return esignCompanyDto;
    }

    /**
     * 经销商印章信息
     *
     * @param partyId
     * @return
     */
    private EsignDealerDto getEsignDealer(Integer partyId) {
        EsignDealerDto esignDealerDto = esignDealerService.getEsignDealerById(partyId);
        if (esignDealerDto == null) {
            throw new BizException(101, "该经销商没有生成印章信息");
        }
        return esignDealerDto;
    }

    /**
     * 查询模板信息
     *
     * @param templateIds
     * @return
     */
    private List<ContractTemplateDto> getContractTemplateList(List<Integer> templateIds) {
        List<ContractTemplateDto> templateList = contractTemplateService.getByIds(templateIds);
        if (CollectionUtils.isEmpty(templateList)) {
            throw new BizException(103, "不存在该模板信息！！！");
        }
        return templateList;
    }


    /**
     * 获取合同编号
     * prefix 里程包合同前缀
     *
     * @return
     */
    private String getContractNumber(String prefix, String brandChannel) {
        for (int i = 0; i < 3; i++) {
            //随机生成物5位数
            String sequence = RandomCode.getSequence(5);
            //合同编号
            String contractNumber = "";
            contractNumber = brandChannel + sequence;
            if (null != prefix) {
                contractNumber = prefix + brandChannel + sequence;
            }
            List<ContractDto> contractList = contractService.getListByContractCode(contractNumber);
            if (contractList == null || contractList.size() == 0) {
                return contractNumber;
            }
        }
        return null;
    }

    /**
     * 获取合同编号
     *
     * @param mainOrderCode
     * @param orderCode
     * @param contractType
     * @return
     */
    private String getContractCode(Long mainOrderCode, Long orderCode, Integer contractType) {
        List<ContractDto> contractDtoList = null;
        if (mainOrderCode != null) {
            contractDtoList = contractService.getContractListByOrderCode(mainOrderCode, contractType);
        } else {
            contractDtoList = contractService.getContractListByOrderCode(orderCode, contractType);
        }
        logger.info("获取合同返回参数：" + JSON.toJSONString(contractDtoList));
        if (null == contractDtoList || contractDtoList.size() == 0) {
            throw new BizException(101, "没有第一笔订单合同信息！！！");
        }
        return contractDtoList.get(0).getContractCode();
    }

    /**
     * 生成合同并盖章
     *
     * @param esignAccountB
     * @param esignAccountBB
     * @param esignCompanyA
     * @param Templates
     * @param dto
     * @return
     * @throws Exception
     */
    private ResponseResult<String> createGeneralAndGuarantee(EsignAccountDto esignAccountB, EsignAccountDto esignAccountBB
            , EsignCompanyDto esignCompanyA, List<ContractTemplateDto> Templates, ContractGeneralBizCreateDto dto, UploadFileRequestDto uploadFileRequestDto) {
        ResponseResult<String> response = new ResponseResult<String>();
        //对象转map
        Map<String, Object> objectToMap;
        try {
            objectToMap = objectToMap(dto);
        } catch (Exception e) {
            response.setMessage("实体转换map异常");
            response.setCode(106);
            logger.error("实体转换map异常！！！", e);
            return response;
        }

        List<ContractDto> list = new ArrayList<>(); // 批量保存数据list
        List<ContractLogDto> contractLogList = new ArrayList<>();
        //获取合同路径文件夹
        String finalFilePath = getFinalFilePath();
        for (ContractTemplateDto contractTemplateDto : Templates) {
            logger.info(" 单个合同模板信息》》》》》》》》" + JSONObject.toJSONString(contractTemplateDto));
            // 获取模板信息
            byte[] templateBytes = fileEhCacheUtil.getTemplate(contractTemplateDto.getName(),
                    contractTemplateDto.getTemplatePath());

            FileCreateFromTemplateResult fileFromTemplate = createPDF(templateBytes, objectToMap, finalFilePath);
            if (fileFromTemplate == null) {
                response.setMessage("合同生成失败");
                response.setCode(106);
                logger.error("合同生成失败！！！");
                return response;
            }
            String filePath = fileFromTemplate.getDstPdfFile();// 合同路径
            SignPDFStreamBean signPDFStreamBean = new SignPDFStreamBean();
            signPDFStreamBean.setDstPdfFile(null);
            signPDFStreamBean.setStream(FileEhCacheUtil.file2byte(filePath));

            //合同盖章位置
            String[] posX = contractTemplateDto.getEsignPosX().split(",");
            String[] posY = contractTemplateDto.getEsignPosY().split(",");
            // 合同甲方盖章
            PosBean posBean = new PosBean();
            posBean.setPosPage(contractTemplateDto.getEsignPosPage());// 页码
            posBean.setPosX(Float.parseFloat(posX[0]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[0])); // 坐标
            FileDigestSignResult fileDigestSignResult = ESignLib.localSignPDFMoliSide(signPDFStreamBean, posBean,
                    esignCompanyA.getSealData(), SignType.Single);
            if (fileDigestSignResult == null) {
                logger.error("甲方盖章失败(FileDigestSignResult is null)！！！" + JSONObject.toJSONString(signPDFStreamBean) + ","
                        + JSONObject.toJSONString(posBean) + "," + SignType.Single);
                response.setCode(107);
                response.setMessage("甲方盖章失败");
                return response;
            } else if (fileDigestSignResult.getErrCode() != 0) {
                logger.error("同甲方盖章失败(" + fileDigestSignResult.getErrCode() + ":"
                        + fileDigestSignResult.getMsg() + ")" + JSONObject.toJSONString(signPDFStreamBean) + ","
                        + JSONObject.toJSONString(posBean) + "," + SignType.Single);
                response.setCode(107);
                response.setMessage("甲方盖章失败(" + fileDigestSignResult.getErrCode() + ":"
                        + fileDigestSignResult.getMsg() + ")");
                return response;
            }

            if (dto.getIsWarrantor() == 1
                    && ContractTypeEnum.GUARANTEE_CONTRACT.getValue() == contractTemplateDto.getTemplateType()) {
                // 担保人合同盖章
                posBean.setPosPage(contractTemplateDto.getEsignPosPage()); // 页码
                posBean.setPosX(Float.parseFloat(posX[1])); // 坐标
                posBean.setPosY(Float.parseFloat(posY[1])); // 坐标
                signPDFStreamBean.setStream(fileDigestSignResult.getStream());
                fileDigestSignResult = localSignPDFCustomerSide(fileDigestSignResult, signPDFStreamBean, posBean, esignAccountBB);

            } else {
                // 主合同乙方盖章
                posBean.setPosPage(contractTemplateDto.getEsignPosPage()); // 页码
                posBean.setPosX(Float.parseFloat(posX[1])); // 坐标
                posBean.setPosY(Float.parseFloat(posY[1])); // 坐标
                signPDFStreamBean.setStream(fileDigestSignResult.getStream());
                fileDigestSignResult = localSignPDFCustomerSide(fileDigestSignResult, signPDFStreamBean, posBean, esignAccountB);
            }
            // 合同丙方盖章
            posBean.setPosPage(contractTemplateDto.getEsignPosPage());// 页码
            posBean.setPosX(Float.parseFloat(posX[2]));// 坐标
            posBean.setPosY(Float.parseFloat(posY[2])); // 坐标
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSide(fileDigestSignResult, signPDFStreamBean, posBean, companySealDataCacheUtil.getPartyCSealData());

            // 盖骑缝章(甲方章)
            posBean.setPosPage(contractTemplateDto.getEsignEdgesPage());// 页码
            posBean.setPosY(Float.parseFloat(contractTemplateDto.getEsignEdgesY()));
            signPDFStreamBean.setStream(fileDigestSignResult.getStream());
            fileDigestSignResult = localSignPDFMoliSideEdges(fileDigestSignResult, signPDFStreamBean, posBean, esignCompanyA.getSealData());

            //盖章完成生成流
            byte[] stream = fileDigestSignResult.getStream();
            String newFileName = "molikejiht-" + UUIDUtil.getUUID() + ".pdf";
            // 上传oss
            String ossPdfUrl = null;
            try {
                ossPdfUrl = byte2FileOss(stream, finalFilePath, newFileName, uploadFileRequestDto);
                logger.info("ossPdfUrl:" + ossPdfUrl);
            } catch (Exception e) {
                logger.error("订单号为：" + dto.getOrderCode() + "合同上传oss失败！！");
                response.setCode(108);
                response.setMessage("订单号为：" + dto.getOrderCode() + "合同上传oss失败！！");
                return response;
            }
            ContractDto contractDto = getGeneralContractDto(ossPdfUrl, dto, contractTemplateDto);
            list.add(contractDto);

            ContractLogDto contractLogDto = createContractLog(dto.getOrderCode(), dto.getBusinessType(), contractDto.getContractCode(), contractDto.getContractName(), null, true);
            contractLogList.add(contractLogDto);
            File file = new File(filePath);
            file.delete();
        }

        // 批量保存数据
        if (list != null && list.size() > 0) {
            contractService.createContractBatch(list);
        }

        // 批量保存数据
        if (contractLogList != null && contractLogList.size() > 0) {
            contractLogService.createContractLogList(contractLogList);
        }
        response.setCode(200);
        response.setData(dto.getContractNumber());
        return response;
    }

    /**
     * 获取合同dto
     *
     * @param ossPdfUrl
     * @param dto
     * @param contractTemplateDto
     * @return
     */
    private ContractDto getGeneralContractDto(String ossPdfUrl, ContractGeneralBizCreateDto dto, ContractTemplateDto contractTemplateDto) {
        ContractDto contractDto = new ContractDto();
        contractDto.setContractPath(ossPdfUrl);
        if (ContractTypeEnum.COMMON_CONTRACT.getValue() == contractTemplateDto.getTemplateType()) {
            contractDto.setContractCode(dto.getContractNumber()); // 合同编号
        } else if (ContractTypeEnum.GUARANTEE_CONTRACT.getValue() == contractTemplateDto.getTemplateType()) {
            contractDto.setContractCode(dto.getGuaranteeNumber());
        }

        contractDto.setOrderCode(dto.getOrderCode());
        contractDto.setContractType(contractTemplateDto.getTemplateType()); // 合同类型（
        contractDto.setContractStatus(ContractStatusEnum.EFFECTIVE.getValue());
        contractDto.setSignedTime(dto.getSignedTime());
        contractDto.setBusinessType(dto.getBusinessType());
        contractDto.setIsCreated(IsDeleteEnum.YES.getValue());
        contractDto.setContractTemplateId(contractTemplateDto.getTemplateId());
        contractDto.setContractTemplatePath(contractTemplateDto.getTemplatePath());
        contractDto.setContractName(contractTemplateDto.getName());
        contractDto.setEndTime(dto.getEndTime());
        contractDto.setEffectiveTime(dto.getEffectiveTime());
        contractDto.setIsEcontract(IsDeleteEnum.YES.getValue());
        contractDto.setGuaranteeType(dto.getIsWarrantor());
        contractDto.setPartyAId(dto.getPartyAId().intValue());
        contractDto.setPartyAName(dto.getPartyAName());
        contractDto.setPartyBId(dto.getPartyBId().intValue());
        contractDto.setPartyBName(dto.getPartyBName());
        contractDto.setPartyCName(dto.getPartyCName());
        Integer contractGuaranteeId = dto.getContractGuaranteeId();
        if (contractGuaranteeId != null && contractGuaranteeId == contractTemplateDto.getTemplateId()) {
            contractDto.setMainOrderCode(dto.getOrderCode());
        }
        return contractDto;
    }


    /**
     * Bean 转 Map
     *
     * @param obj
     * @return
     * @throws Exception
     */
    public Map<String, Object> objectToMap(Object obj) throws Exception {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            map.put(field.getName(), field.get(obj));
        }
        return map;
    }

    /**
     * 获取合同路径文件夹
     *
     * @return
     */
    private String getFinalFilePath() {
        String finalFilePath = CONTRACT_FILE_PATH;
        File dirPath = new File(finalFilePath);
        if (!dirPath.exists()) {
            dirPath.mkdirs();
        }
        return finalFilePath;
    }

    /**
     * 根据参数生成不同的合同pdf文件
     *
     * @return
     */
    public FileCreateFromTemplateResult createPDF(byte[] templateBytes, Map<String, Object> map, String path) {
        logger.info("sys生成pdf参数 map" + map.toString() + ",path:" + path);
        SignPDFStreamBean signPDFStreamBean = new SignPDFStreamBean();
        signPDFStreamBean.setStream(templateBytes);
        signPDFStreamBean.setDstPdfFile(path);

        FileCreateFromTemplateResult fileFromTemplate = null;
        try {
            // 拿到对应的信息，由模板生成PDF合同
            fileFromTemplate = ESignLib.createFileFromTemplate(signPDFStreamBean, true, map);
            if (fileFromTemplate.getErrCode() != 0) {
                logger.error("模板生成失败(" + fileFromTemplate.getMsg() + ")" + JSONObject.toJSONString(signPDFStreamBean) + ","
                        + true + "," + map.toString());
                return null;
            }
        } catch (Exception e) {
            logger.error("模板生成失败:", e);
        }

        return fileFromTemplate;
    }

    /**
     * 个人盖章
     *
     * @param fileDigestSignResult
     * @param signPDFStreamBean
     * @param posBean
     * @param esignAccountB
     * @return
     */
    private FileDigestSignResult localSignPDFCustomerSide(FileDigestSignResult fileDigestSignResult, SignPDFStreamBean signPDFStreamBean, PosBean posBean, EsignAccountDto esignAccountB) {
        fileDigestSignResult = ESignLib.localSignPDFCustomerSide(esignAccountB.getAccountId(),
                esignAccountB.getSealData(), signPDFStreamBean, posBean, SignType.Single);
        if (fileDigestSignResult == null) {
            logger.error("个人盖章失败(FileDigestSignResult is null)！！！" + esignAccountB.getAccountId() + ","
                    + JSONObject.toJSONString(signPDFStreamBean) + ","
                    + JSONObject.toJSONString(posBean) + "," + SignType.Single);
            throw new BizException(107, "个人盖章失败！！！");
        } else if (fileDigestSignResult.getErrCode() != 0) {
            logger.error("个人盖章失败(" + fileDigestSignResult.getErrCode() + ":"
                    + fileDigestSignResult.getMsg() + ")" + esignAccountB.getAccountId() + ","
                    + JSONObject.toJSONString(signPDFStreamBean) + ","
                    + JSONObject.toJSONString(posBean) + "," + SignType.Single);
            throw new BizException(107, "个人盖章失败(" + fileDigestSignResult.getErrCode() + ":"
                    + fileDigestSignResult.getMsg() + ")");
        }
        return fileDigestSignResult;
    }


    /**
     * 公司盖章
     *
     * @param fileDigestSignResult
     * @param signPDFStreamBean
     * @param posBean
     * @param sealData
     * @return
     */
    private FileDigestSignResult localSignPDFMoliSide(FileDigestSignResult fileDigestSignResult, SignPDFStreamBean signPDFStreamBean, PosBean posBean, String sealData) {
        fileDigestSignResult = ESignLib.localSignPDFMoliSide(signPDFStreamBean, posBean,
                sealData, SignType.Single);
        if (fileDigestSignResult == null) {
            logger.error("公司盖章失败(FileDigestSignResult is null)！！！" + JSONObject.toJSONString(signPDFStreamBean) + ","
                    + JSONObject.toJSONString(posBean) + "," + SignType.Single);
            throw new BizException(107, "公司盖章失败！！！");
        } else if (fileDigestSignResult.getErrCode() != 0) {
            logger.error("公司盖章失败(" + fileDigestSignResult.getErrCode() + ":"
                    + fileDigestSignResult.getMsg() + ")" + JSONObject.toJSONString(signPDFStreamBean) + ","
                    + JSONObject.toJSONString(posBean) + "," + SignType.Single);
            throw new BizException(107, "公司盖章失败(" + fileDigestSignResult.getErrCode() + ":"
                    + fileDigestSignResult.getMsg() + ")");
        }
        return fileDigestSignResult;
    }

    /**
     * 公司盖章骑缝章
     *
     * @param fileDigestSignResult
     * @param signPDFStreamBean
     * @param posBean
     * @param sealData
     * @return
     */
    private FileDigestSignResult localSignPDFMoliSideEdges(FileDigestSignResult fileDigestSignResult, SignPDFStreamBean signPDFStreamBean, PosBean posBean, String sealData) {
        fileDigestSignResult = ESignLib.localSignPDFMoliSide(signPDFStreamBean, posBean,
                sealData, SignType.Edges);
        if (fileDigestSignResult == null) {
            logger.error("公司盖章失败(FileDigestSignResult is null)！！！" + JSONObject.toJSONString(signPDFStreamBean) + ","
                    + JSONObject.toJSONString(posBean) + "," + SignType.Edges);
            throw new BizException(107, "公司盖章失败！！！");
        } else if (fileDigestSignResult.getErrCode() != 0) {
            logger.error("公司盖章失败(" + fileDigestSignResult.getErrCode() + ":"
                    + fileDigestSignResult.getMsg() + ")" + JSONObject.toJSONString(signPDFStreamBean) + ","
                    + JSONObject.toJSONString(posBean) + "," + SignType.Edges);
            throw new BizException(107, "公司盖章失败(" + fileDigestSignResult.getErrCode() + ":"
                    + fileDigestSignResult.getMsg() + ")");
        }
        return fileDigestSignResult;
    }

    /**
     * 获取模板
     *
     * @param templateType
     * @return
     */
    private List<ContractTemplateDto> getContractTemplates(Integer templateType) {
        List<ContractTemplateDto> templateList = contractTemplateService.getByTemplateType(templateType);
        if (null == templateList || templateList.size() == 0) {
            throw new BizException(103, "不存在该模板信息！！！");
        }
        return templateList;
    }

    /**
     * 上传oss
     *
     * @param bfile
     * @param filePath
     * @param fileName
     * @return
     * @throws Exception
     */
    private String byte2FileOss(byte[] bfile, String filePath, String fileName, UploadFileRequestDto uploadFileRequestDto) throws Exception {
        UploadFileResponseDto uploadFileResponseDto = UploadUtil.uploadByteToAll(bfile, fileName, uploadFileRequestDto);
        return uploadFileResponseDto.getFileUrl();

        /*BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {
            File dir = new File(filePath);
            if (!dir.exists() && !dir.isDirectory()) {//判断文件目录是否存在
                dir.mkdirs();
            }
            file = new File(filePath + "//" + fileName);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bfile);
        } catch (Exception e) {
            logger.error("根据流保存文件异常", e);
        } finally {
            try {
                if (bos != null) {
                    bos.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (Exception e) {
                logger.error("关流异常", e);
            }
        }
        //TODO 上传到oss 返回上传路径
        //String ossUrl = ossUtil.uploadToOss(file, 2, "contract");
        String ossUrl = "";
        file.delete();
        return ossUrl;*/
    }


    /**
     * 专用条款和补充协议计算数据
     *
     * @param dto
     * @return
     */
    private ContractSupplementBizCreateDto getUsedcarSpecialTemplateDto(ContractSupplementBizCreateDto dto) {
        // 补充协议需要处理的逻辑
        List<ContractDto> contractDtoList = null;
        contractDtoList = contractService.getContractListByOrderCode(dto.getOrderCode(), ContractTypeEnum.COMMON_CONTRACT.getValue());
        logger.info("生成补充协议，查询主合同编号" + JSONObject.toJSONString(contractDtoList));
        String contractCode = "";
        if (contractDtoList != null && contractDtoList.size() > 0) {
            ContractDto contractDto = contractDtoList.get(0);
            contractCode = contractDto.getContractCode();
            logger.info("主合同编号：" + contractCode);
            dto.setContractNumber(contractCode);
            dto.setDedicateNumber(contractCode + "-1");
            dto.setSupplementaryNumber(contractCode + "-2");
            /**
             * 合同签署日期（2.1.0 新增字段），为了兼容2.0.1版本
             * 当合同签署日期为null时，就用该合同记录的创建时间
             *
             */
            LocalDateTime signedTime = contractDto.getSignedTime();
            String date = DateUtil.formatDate(signedTime);
            String[] dateList = date.split("-");
            //主合同年
            dto.setSigningYear(dateList[0]);
            //主合同月
            dto.setSigningMonth(dateList[1]);
            //主合同日
            dto.setSigningDay(dateList[2]);
        } else {
            throw new IllegalArgumentException("生成补充协议》》》》通过订单编号查询主合同失败！！" + JSONObject.toJSONString(dto));
        }
        //基础回购价格
        BigDecimal repurchaseFee = dto.getRepurchaseFee();
        //过户费
        BigDecimal transferFee = dto.getTransferFee();
        if (repurchaseFee != null) {
            dto.setRepurchaseFeeUpper(NumberToCNUtils.number2CNMontrayUnit(repurchaseFee));
        }
        if (transferFee != null) {
            dto.setTransferFeeUpper(NumberToCNUtils.number2CNMontrayUnit(transferFee));
        }

        //专用条款需要处理逻辑
        dto.setDedicateNumber(contractCode + "-1");
        BigDecimal totalFee = dto.getTotalFee();
        BigDecimal depositFee = dto.getDepositFee();
        //数字装大写租赁费用总计
        if (totalFee != null) {
            dto.setTotalFeeUpper(NumberToCNUtils.number2CNMontrayUnit(totalFee));
        }
        //数字装大写保证金
        if (depositFee != null) {
            dto.setDepositFeeUpper(NumberToCNUtils.number2CNMontrayUnit(depositFee));
        }
        //是否有担保人 0 ：无，1 ：有
        Integer isWarrantor = dto.getIsWarrantor();
        if (null != isWarrantor && isWarrantor == 1) { //有担保人
            dto.setIsGuarantee("是");
            dto.setGuaranteeType("保证人担保");
        } else {//无担保人
            dto.setIsGuarantee("否");
            dto.setGuaranteeType("无");
            dto.setWarrantorName("无");
            dto.setWarrantorPhone("无");
            dto.setWarrantorCard("无");
        }
        return dto;
    }

    /**
     * 参数验证
     *
     * @param dto
     */
    private ParamTemplateBizCreateDto validationParam(ContractDeliveryBizCreateDto dto) {
        ParamTemplateBizCreateDto templateDto = new ParamTemplateBizCreateDto();
        Assert.notNull(dto, "参数实体不能为空");
        Assert.notNull(dto.getOrderCode(), "参数orderCode不能为空");
        Assert.hasText(dto.getVin(), "参数vin不能为空");
        templateDto.setVin(dto.getVin());
        Assert.hasText(dto.getGoodsName(), "参数goodsName不能为空");
        templateDto.setGoodsName(dto.getGoodsName());
        Assert.hasText(dto.getLicencePlate(), "参数licencePlate不能为空");
        templateDto.setLicencePlate(dto.getLicencePlate());
        Assert.hasText(dto.getColorName(), "参数colorName不能为空");
        Assert.hasText(dto.getModelName(), "参数modelName不能为空");
        templateDto.setColorName(dto.getColorName());
        Assert.hasText(dto.getPartyAName(), "参数partyAName不能为空");
        Assert.notNull(dto.getPartyAId(), "参数partyAId不能为空");
        Assert.hasText(dto.getPartyBName(), "参数partyBName不能为空");
        templateDto.setPartyBName(dto.getPartyBName());
        Assert.notNull(dto.getPartyBId(), "参数partyBId不能为空");
        Assert.hasText(dto.getPartyBPhone(), "参数partyBPhone不能为空");
        templateDto.setPartyBPhone(dto.getPartyBPhone());
        Assert.hasText(dto.getPartyBCard(), "参数partyBCard不能为空");
        Assert.hasText(dto.getEmployeeName(), "参数employeeName不能为空");
        templateDto.setEmployeeName(dto.getEmployeeName());
        Assert.hasText(dto.getCarStoresAddress(), "参数carStoresAddress不能为空");
        templateDto.setCarStoresAddress(dto.getCarStoresAddress());
        Assert.notNull(dto.getIsWarrantor(), "参数isWarrantor不能为空");
        Assert.notNull(dto.getMileage(), "参数mileage不能为空");
        templateDto.setMileage(dto.getMileage() + "");
        Assert.notNull(dto.getCarKeyStatus(), "参数carKeyStatus不能为空");
        templateDto.setCarKeyStatus(dto.getCarKeyStatus());
        Assert.notNull(dto.getBusinessType(), "参数businessType不能为空");
        if (dto.getBusinessType().equals(ContractBusinessTypeEnum.SUBSCRIBE.getValue())) {
            Assert.notNull(dto.getHandoverType(), "参数handoverType不能为空");
            templateDto.setHandoverTypeStr(OrderHandoverTypeEnum.getName(dto.getHandoverType()));
            //交接类型（1：提车，2：还车，3：验车单）
            if (OrderHandoverTypeEnum.SURVEY_REPORT_VEHICLE.getValue() == dto.getHandoverType()) {
                Assert.hasLength(dto.getEngineCode(), "参数engineCode不能为空");
                templateDto.setEngineCode(dto.getEngineCode());
                Assert.hasLength(dto.getCheckDate(), "参数checkDate不能为空");
                templateDto.setCheckDate(dto.getCheckDate());
                Assert.hasLength(dto.getCheckAddress(), "参数checkAddress不能为空");
                templateDto.setCheckAddress(dto.getCheckAddress());
                templateDto.setRemark(dto.getRemark());
                templateDto.setMassLossFee(dto.getMassLossFee());
                templateDto.setOvertimeFee(dto.getOvertimeFee());
                templateDto.setOverMileageFee(dto.getOverMileageFee());
                templateDto.setCustomerDisapproveRemark(dto.getCustomerDisapproveRemark());
                templateDto.setServiceRemark(dto.getServiceRemark());
                Assert.hasLength(dto.getPreparingPerson(), "参数preparingPerson不能为空");
                templateDto.setPreparingPerson(dto.getPreparingPerson());
            }
        } else {
            Assert.notNull(dto.getLease(), "参数lease不能为空");
            templateDto.setLeaseStr(dto.getLease() + "个月");
        }
        Assert.notNull(dto.getDrivingLicenseStatus(), "参数drivingLicenseStatus不能为空");
        if (dto.getDrivingLicenseStatus() == 0) {
            templateDto.setDrivingLicenseStatusStr(YES);
        } else {
            templateDto.setDrivingLicenseStatusStr(NO);
        }
        Assert.notNull(dto.getMakeStrongStatus(), "参数makeStrongStatus不能为空");
        if (dto.getMakeStrongStatus() == 0) {
            templateDto.setMakeStrongStatusStr(YES);
        } else {
            templateDto.setMakeStrongStatusStr(NO);
        }
        Assert.notNull(dto.getAnnualStatus(), "参数annualStatus不能为空");
        if (dto.getAnnualStatus() == 0) {
            templateDto.setAnnualStatusStr(YES);
        } else {
            templateDto.setAnnualStatusStr(NO);
        }
        Assert.notNull(dto.getGuaranteeStatus(), "参数guaranteeStatus不能为空");
        if (dto.getGuaranteeStatus() == 0) {
            templateDto.setGuaranteeStatusStr(YES);
        } else {
            templateDto.setGuaranteeStatusStr(NO);
        }
        Assert.notNull(dto.getWheelHubStatus(), "参数wheelHubStatus不能为空");
        if (dto.getWheelHubStatus() == 0) {
            templateDto.setWheelHubStatusStr(YES);
        } else {
            templateDto.setWheelHubStatusStr(NO);
        }
        Assert.notNull(dto.getTyreStatus(), "参数tyreStatus不能为空");
        if (dto.getTyreStatus() == 0) {
            templateDto.setTyreStatusStr(YES);
        } else {
            templateDto.setTyreStatusStr(NO);
        }
        Assert.notNull(dto.getLamplightStatus(), "参数lamplightStatus不能为空");
        if (dto.getLamplightStatus() == 0) {
            templateDto.setLamplightStatusStr(YES);
        } else {
            templateDto.setLamplightStatusStr(NO);
        }
        Assert.notNull(dto.getInstrumentPanelStatus(), "参数instrumentPanelStatus不能为空");
        if (dto.getInstrumentPanelStatus() == 0) {
            templateDto.setInstrumentPanelStatusStr(YES);
        } else {
            templateDto.setInstrumentPanelStatusStr(NO);
        }
        Assert.notNull(dto.getSounderStatus(), "参数sounderStatu不能为空");
        if (dto.getSounderStatus() == 0) {
            templateDto.setSounderStatusStr(YES);
        } else {
            templateDto.setSounderStatusStr(NO);
        }
        Assert.notNull(dto.getWiperStatus(), "参数wiperStatus不能为空");
        if (dto.getWiperStatus() == 0) {
            templateDto.setWiperStatusStr(YES);
        } else {
            templateDto.setWiperStatusStr(NO);
        }
        Assert.notNull(dto.getTrumpetStatus(), "参数trumpetStatus不能为空");
        if (dto.getTrumpetStatus() == 0) {
            templateDto.setTrumpetStatusStr(YES);
        } else {
            templateDto.setTrumpetStatusStr(NO);
        }
        Assert.notNull(dto.getAirConditionerStatus(), "参数airConditionerStatus不能为空");
        if (dto.getAirConditionerStatus() == 0) {
            templateDto.setAirConditionerStatusStr(YES);
        } else {
            templateDto.setAirConditionerStatusStr(NO);
        }
        Assert.notNull(dto.getSeatStatus(), "参数seatStatus不能为空");
        if (dto.getSeatStatus() == 0) {
            templateDto.setSeatStatusStr(YES);
        } else {
            templateDto.setSeatStatusStr(NO);
        }
        Assert.notNull(dto.getSafetyBeltStatus(), "参数safetyBeltStatus不能为空");
        if (dto.getSafetyBeltStatus() == 0) {
            templateDto.setSafetyBeltStatusStr(YES);
        } else {
            templateDto.setSafetyBeltStatusStr(NO);
        }
        Assert.notNull(dto.getInteriorMirrorStatus(), "参数interiorMirrorStatus不能为空");
        if (dto.getInteriorMirrorStatus() == 0) {
            templateDto.setInteriorMirrorStatusStr(YES);
        } else {
            templateDto.setInteriorMirrorStatusStr(NO);
        }
        Assert.notNull(dto.getWarrantyManualStatus(), "参数warrantyManualStatus不能为空");
        if (dto.getWarrantyManualStatus() == 0) {
            templateDto.setWarrantyManualStatusStr(YES);
        } else {
            templateDto.setWarrantyManualStatusStr(NO);
        }
        Assert.notNull(dto.getSpecificationStatus(), "参数specificationStatus不能为空");
        if (dto.getSpecificationStatus() == 0) {
            templateDto.setSpecificationStatusStr(YES);
        } else {
            templateDto.setSpecificationStatusStr(NO);
        }
        Assert.notNull(dto.getChargingGunStatus(), "参数chargingGunStatus不能为空");
        if (dto.getChargingGunStatus() == 0) {
            templateDto.setChargingGunStatusStr(YES);
        } else {
            templateDto.setChargingGunStatusStr(NO);
        }
        Assert.notNull(dto.getPowerBankStatus(), "参数powerBankStatus不能为空");
        if (dto.getPowerBankStatus() == 0) {
            templateDto.setPowerBankStatusStr(YES);
        } else {
            templateDto.setPowerBankStatusStr(NO);
        }
        Assert.notNull(dto.getFireExtinguisherStatus(), "参数fireExtinguisherStatus不能为空");
        if (dto.getFireExtinguisherStatus() == 0) {
            templateDto.setFireExtinguisherStatusStr(YES);
        } else {
            templateDto.setFireExtinguisherStatusStr(NO);
        }
        Assert.notNull(dto.getTriangleBrandStatus(), "参数triangleBrandStatus不能为空");
        if (dto.getTriangleBrandStatus() == 0) {
            templateDto.setTriangleBrandStatusStr(YES);
        } else {
            templateDto.setTriangleBrandStatusStr(NO);
        }
        Assert.notNull(dto.getReflectiveVestStatus(), "参数reflectiveVestStatus不能为空");
        if (dto.getReflectiveVestStatus() == 0) {
            templateDto.setReflectiveVestStatusStr(YES);
        } else {
            templateDto.setReflectiveVestStatusStr(NO);
        }
        Assert.notNull(dto.getFootPadStatus(), "参数footPadStatus不能为空");
        if (dto.getFootPadStatus() == 0) {
            templateDto.setFootPadStatusStr(YES);
        } else {
            templateDto.setFootPadStatusStr(NO);
        }
        Assert.notNull(dto.getCarUrl(), "参数carUrl不能为空");
        Assert.notNull(dto.getSigningDate(), "参数signingDate不能为空");
        templateDto.setSigningDate(dto.getSigningDate());
        Assert.notNull(dto.getEndTime(), "参数expirationTime不能为空");
        Assert.notNull(dto.getSignedTime(), "参数signedTime不能为空");
        if (StringUtils.isNoneBlank(dto.getExpandField())) {
            JSONObject parseObject = JSONObject.parseObject(dto.getExpandField());
            if (null != parseObject.get("mileage")) {
                templateDto.setMileage(parseObject.getString("mileage"));
            }
            if (null != parseObject.get("carStatus")) {
                templateDto.setCarStatus(parseObject.getString("carStatus"));
            }
            if (null != parseObject.get("facadeStatusStr")) {
                templateDto.setFacadeStatusStr(parseObject.getString("facadeStatusStr"));
            }
        }
        return templateDto;
    }


    /**
     * 业务类型判断
     *
     * @param dto
     * @param contractDtoList
     * @return
     */
    private List<ContractTemplateDto> businessTypeJudge(ContractDeliveryBizCreateDto dto, List<ContractDto> contractDtoList) {
        //合同模板变量
        List<ContractTemplateDto> templates = null;
        if (ContractBusinessTypeEnum.EXCLUSIVEL.getValue() == dto.getBusinessType()) {
            Integer handoverType = dto.getHandoverType();
            if (handoverType != null && OrderHandoverTypeEnum.DELIVERY_OF_VEHICLE.getValue() == handoverType) {
                //查询该订单是否已经生成过交车单
                getContractIsExist(dto.getOrderCode(), ContractTypeEnum.CAR_CONTRACT.getValue());
                //交车单模板类型
                templates = getContractTemplates(ContractTypeEnum.CAR_CONTRACT.getValue());
            } else if (handoverType != null && OrderHandoverTypeEnum.TRANSFER_VEHICLE.getValue() == dto.getHandoverType()) {
                //查询该订单是否已经生成过交车单
                getContractIsExist(dto.getOrderCode(), ContractTypeEnum.DEDICATED_RETURN_CAR.getValue());
                //交车单模板类型
                templates = getContractTemplates(ContractTypeEnum.DEDICATED_RETURN_CAR.getValue());
            }

            //查看是否生成主合同
            List<ContractDto> tmp = contractService.getContractListByOrderCode(dto.getOrderCode(), ContractTypeEnum.COMMON_CONTRACT.getValue());
            if (null != tmp && tmp.size() > 0) {
                contractDtoList.addAll(tmp);
            }
        } else if (ContractBusinessTypeEnum.SUBSCRIBE.getValue() == dto.getBusinessType()) {
            Integer handoverType = dto.getHandoverType();
            if (handoverType != null && OrderHandoverTypeEnum.DELIVERY_OF_VEHICLE.getValue() == handoverType) {
                //查询该订单是否已经生成过交车单
                getContractIsExist(dto.getOrderCode(), ContractTypeEnum.MILEAGE_BAG_CAR_CONTRACT.getValue());
                //交车单模板类型
                templates = getContractTemplates(ContractTypeEnum.MILEAGE_BAG_CAR_CONTRACT.getValue());
            } else if (handoverType != null && OrderHandoverTypeEnum.TRANSFER_VEHICLE.getValue() == dto.getHandoverType()) {
                //查询该订单是否已经生成过交车单
                getContractIsExist(dto.getOrderCode(), ContractTypeEnum.MILEAGE_BAG_RETURN_CAR.getValue());
                //交车单模板类型
                templates = getContractTemplates(ContractTypeEnum.MILEAGE_BAG_RETURN_CAR.getValue());
            } else if (handoverType != null && OrderHandoverTypeEnum.SURVEY_REPORT_VEHICLE.getValue() == dto.getHandoverType()) {
                //查询该订单是否已经生成过验车报告
                getContractIsExist(dto.getOrderCode(), ContractTypeEnum.MILEAGE_BAG_VALIDATE_CONTRACT.getValue());
                //交车单模板类型
                templates = getContractTemplates(ContractTypeEnum.MILEAGE_BAG_VALIDATE_CONTRACT.getValue());
            }
            //查看是否生成主合同
            if (dto.getMainOrderCode() != null) {
                logger.info("根据主订单号查询主合同 》》》》》》》》入参" + dto.getMainOrderCode());
                List<ContractDto> mainContractList = contractService.getContractListByOrderCode(dto.getMainOrderCode(), ContractTypeEnum.MILEAGE_BAG_CONTRACT.getValue());
                if (null != mainContractList && mainContractList.size() > 0) {
                    contractDtoList.addAll(mainContractList);
                }
                logger.info("根据订单号查询主合同 》》》》》》》》出参" + JSONObject.toJSONString(contractDtoList));
            } else {
                logger.info("根据订单号查询主合同 》》》》》》》》入参" + dto.getOrderCode());
                List<ContractDto> mainContractList = contractService.getContractListByOrderCode(dto.getOrderCode(), ContractTypeEnum.MILEAGE_BAG_CONTRACT.getValue());
                if (null != mainContractList && mainContractList.size() > 0) {
                    contractDtoList.addAll(mainContractList);
                }
                logger.info("根据订单号查询主合同 》》》》》》》》出参" + JSONObject.toJSONString(contractDtoList));
            }
        }
        return templates;
    }


    /**
     * 获取文件最终名称（包括路径）
     *
     * @return
     */
    private String getFinalName(String finalFilePath, String url) {
        url = url.substring(url.lastIndexOf("."));
        long time = System.currentTimeMillis();
        return finalFilePath + File.separator + time + url;
    }


    /**
     * 链接url下载图片
     *
     * @param urlList
     * @param path
     * @return
     */
    private ResponseResult<Boolean> downloadPicture(ResponseResult<Boolean> response, String urlList, String path) {
        URL url = null;
        DataInputStream dataInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            url = new URL(urlList);
            dataInputStream = new DataInputStream(url.openStream());
            fileOutputStream = new FileOutputStream(new File(path));
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = dataInputStream.read(buffer)) > 0) {
                output.write(buffer, 0, length);
            }
            fileOutputStream.write(output.toByteArray());
            response.setCode(200);
            response.setData(true);
        } catch (Exception e) {
            logger.error("链接url下载图片异常", e);
            response.setCode(500);
            response.setData(false);
            response.setMessage("链接url下载图片异常");
        } finally {
            if (null != fileOutputStream) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    logger.error("链接url下载图片 关流fileOutputStream.close() 异常", e);
                }
            }
            if (null != dataInputStream) {
                try {
                    dataInputStream.close();
                } catch (IOException e) {
                    logger.error("链接url下载图片 关流dataInputStream.close() 异常", e);
                }
            }
        }
        return response;
    }

    /**
     * PDF中插入图片
     *
     * @param response
     * @param templatePath
     * @param targetPath
     * @param imagePath
     * @return
     */
    private ResponseResult<Boolean> pdfAddImage(ResponseResult<Boolean> response,
                                                String templatePath, String targetPath, String imagePath) {
        InputStream input = null;
        PdfReader reader = null;
        PdfStamper stamper = null;
        try {
            // 书签名  就是模板中文本框的名称
            String fieldName = "image";
            // 读取模板文件
            input = new FileInputStream(new File(templatePath));
            reader = new PdfReader(input);
            stamper = new PdfStamper(reader, new FileOutputStream(targetPath));
            // 提取pdf中的表单
            AcroFields form = stamper.getAcroFields();
            form.addSubstitutionFont(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED));
            // 通过域名获取所在页和坐标，左下角为起点
            int pageNo = form.getFieldPositions(fieldName).get(0).page;
            Rectangle signRect = form.getFieldPositions(fieldName).get(0).position;
            float x = signRect.getLeft();
            float y = signRect.getBottom();
            // 读图片
            Image image = Image.getInstance(imagePath);
            // 获取操作的页面
            PdfContentByte under = stamper.getOverContent(pageNo);
            // 根据域的大小缩放图片
            image.scaleToFit(signRect.getWidth(), signRect.getHeight());
            // 添加图片
            image.setAbsolutePosition(x, y);
            under.addImage(image);
            response.setCode(200);
            response.setData(true);
        } catch (Exception e) {
            logger.error("PDF中插入图片异常", e);
            response.setCode(500);
            response.setData(false);
            response.setMessage("PDF中插入图片异常");
        } finally {
            if (null != stamper) {
                try {
                    stamper.close();
                } catch (DocumentException | IOException e) {
                    logger.error("PDF中插入图片 stamper.close()关流 异常", e);
                }
            }
            if (null != reader) {
                reader.close();
            }
            //删除图片
            File file = new File(imagePath);
            file.delete();
        }
        return response;
    }

    /**
     * 修改合同状态
     *
     * @param orderCode
     * @param contractStatus
     * @return
     */
    private Boolean mpdifyContractStatus(Long orderCode, Integer contractStatus) {
        return contractService.modifyStatusByOrderCode(orderCode, contractStatus);
    }

    /**
     * 修改合同状态
     *
     * @param mainOrderCode
     * @param contractStatus
     * @return
     */
    private Boolean modifyStatusByMainOrderCode(Long mainOrderCode, Integer contractStatus) {
        return contractService.modifyStatusByMainOrderCode(mainOrderCode, contractStatus);
    }

    /**
     * 采购合同
     *
     * @param dto
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean createPurchaseContract(ContractPurchaseBizCreateDto dto) throws Exception {
        createPurchaseContractCheck(dto);
        List<ContractImageBizCreateDto> list = dto.getList();
        Integer contractType = dto.getContractType();
        Long orderCode = dto.getOrderCode();

        ContractCreateDto contractCreateDto = Convert.toContractCreateDto(dto);
        if (contractType != null && ContractTypeEnum.EXCLUSIVE_BOOKING_CONTRACT.getValue() == contractType) {
            String contractNumber = getContractNumber(null, "CC");
            contractCreateDto.setContractCode(contractNumber);
            contractCreateDto.setBusinessType(ContractBusinessTypeEnum.CC.getValue());
        } else if (contractType != null && ContractTypeEnum.EXCLUSIVE_BOOKING_CAR_CONTRACT.getValue() == contractType) {
            String contractNumber = getContractCode(null, orderCode, ContractTypeEnum.EXCLUSIVE_BOOKING_CONTRACT.getValue());
            contractCreateDto.setContractCode(contractNumber + "(1)");
            contractCreateDto.setBusinessType(ContractBusinessTypeEnum.CC.getValue());
        } else {
            contractCreateDto.setContractType(ContractTypeEnum.PURCHASE_CONTRACT.getValue());
            contractCreateDto.setBusinessType(ContractBusinessTypeEnum.DEALER.getValue());
        }
        contractCreateDto.setIsCreated(IsDeleteEnum.YES.getValue());
        contractCreateDto.setIsEcontract(IsDeleteEnum.YES.getValue());
        // 判断生成合同类型
        if (contractCreateDto.getContractType() != null &&
                (contractCreateDto.getContractType() == ContractTypeEnum.CAR_CONTRACT.getValue()
                        || contractCreateDto.getContractType() == ContractTypeEnum.DEDICATED_RETURN_CAR.getValue()
                        || contractCreateDto.getContractType() == ContractTypeEnum.MILEAGE_BAG_CAR_CONTRACT.getValue()
                        || contractCreateDto.getContractType() == ContractTypeEnum.MILEAGE_BAG_RETURN_CAR.getValue())) {
            // 交车单或者还车单，生成直接已终止
            contractCreateDto.setContractStatus(ContractStatusEnum.TERMINATED.getValue());
        } else {
            contractCreateDto.setContractStatus(ContractStatusEnum.EFFECTIVE.getValue());
        }
        contractCreateDto.setGuaranteeType(0);
        Integer contractId = contractService.createContract(contractCreateDto);
        if (list != null && list.size() > 0) {
            List<ContractImageCreateDto> contractImageList = Convert.toContractImageCreateDtoList(list, contractId);
            Boolean contractImageBoolean = contractImageService.createContractImageBatch(contractImageList);
            if (!contractImageBoolean) {
                return false;
            }
        }

        return true;
    }

    /**
     * 校验
     *
     * @param dto
     * @throws Exception
     */
    private void createPurchaseContractCheck(ContractPurchaseBizCreateDto dto) throws Exception {
        if (null == dto) {
            throw new BizException("合同生成失败，入参为空");
        }

        String contractCode = dto.getContractCode();
        List<ContractImageBizCreateDto> list = dto.getList();
        Integer contractType = dto.getContractType();
        Long orderCode = dto.getOrderCode();

        getContractIsExist(orderCode, contractType);
        if (StringUtils.isNoneBlank(contractCode)) {
            Boolean contractCodeExistBoolean = contractService.getContractCodeExist(contractCode);
            if (contractCodeExistBoolean) {
                throw new BizException("合同编号" + contractCode + "已存在，请输入正确合同编号");
            }
        }

        if (null == contractType || (ContractTypeEnum.EXCLUSIVE_BOOKING_CONTRACT.getValue() != contractType && ContractTypeEnum.EXCLUSIVE_BOOKING_CAR_CONTRACT.getValue() != contractType)) {
            for (ContractImageBizCreateDto contractImageBizCreateDto : list) {
                String name = contractImageBizCreateDto.getName();
                Boolean imageNameExist = contractImageService.getImageNameExist(name);
                if (imageNameExist) {
                    throw new BizException(name + "已存在，不允许重复上传");
                }
            }
        }
    }

    /**
     * 查询采购合同
     *
     * @return
     */
    @Override
    public ContractPurchaseBizDto getPurchaseContract(Long orderCode) {
        List<ContractDto> contractDtoList = contractService.getContractListByOrderCode(orderCode, null);
        if (null == contractDtoList || contractDtoList.size() < 1) {
            return null;
        }
        ContractDto contractDto = contractDtoList.get(0);
        if (null == contractDto) {
            return null;
        }

        ContractPurchaseBizDto contractPurchaseBizDto = Convert.toContractPurchaseBizDto(contractDto);
        Integer contractId = contractDto.getContractId();
        List<ContractImageDto> contractImageList = contractImageService.getContractImageList(contractId);
        if (contractImageList != null && contractImageList.size() > 0) {
            List<ContractImageBizDto> contractImageBizList = Convert.toContractImageBizDtoList(contractImageList);
            contractPurchaseBizDto.setList(contractImageBizList);
        }

        return contractPurchaseBizDto;
    }

    /**
     * 订悦提车单
     *
     * @param dto
     * @return
     * @throws Exception
     */
    @Override
    public Boolean createBookingCarContract(ContractBookingCarBizCreateDto dto) throws Exception {
        if (null == dto) {
            throw new BizException("合同生成失败，入参为空");
        }
        Integer contractType = dto.getContractType();
        Long orderCode = dto.getOrderCode();
        Integer businessType = dto.getBusinessType();
        if (null == contractType) {
            throw new BizException("合同类型不能为空");
        }
        if (null == businessType) {
            throw new BizException("合同业务类型不能为空");
        }

        getContractIsExist(orderCode, contractType);
        Integer mainContractType = null;
        if (businessType != null && ContractBusinessTypeEnum.CC.getValue() == businessType) {
            mainContractType = ContractTypeEnum.EXCLUSIVE_BOOKING_CONTRACT.getValue();
        }
        List<ContractDto> bookingContractList = contractService.getContractListByOrderCode(orderCode, mainContractType);
        if (null == bookingContractList || bookingContractList.size() < 1) {
            throw new BizException("通过订单编号查询主合同失败");
        }

        ContractCreateDto contractCreateDto = Convert.toContractCreateDto(dto);
        String contractNumber = bookingContractList.get(0).getContractCode() + "(1)";
        contractCreateDto.setContractCode(contractNumber);
        contractCreateDto.setIsCreated(IsDeleteEnum.YES.getValue());
        contractCreateDto.setIsEcontract(IsDeleteEnum.YES.getValue());
        contractCreateDto.setContractStatus(ContractStatusEnum.EFFECTIVE.getValue());
        contractCreateDto.setGuaranteeType(0);
        contractService.createContract(contractCreateDto);
        return true;
    }

    /**
     * 获取合同模板map
     *
     * @param businessType
     * @return
     */
    private Map<Integer, Integer> getContractTemplateMap(Integer businessType) {
        List<ContractTemplateDto> contractTemplateList = contractTemplateService.getByGoodsType(businessType);
        if (null == contractTemplateList || contractTemplateList.size() < 1) {
            return null;
        }

        Map<Integer, Integer> returnMap = new HashMap<>();
        for (ContractTemplateDto contractTemplateDto : contractTemplateList) {
            Integer templateType = contractTemplateDto.getTemplateType();
            Integer templateId = contractTemplateDto.getTemplateId();
            returnMap.put(templateType, templateId);
        }
        return returnMap;
    }

    /**
     * 解除协议
     *
     * @param createDto
     * @param uploadFileRequestDto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean createRenege(ContractRenegeBizCreateDto createDto, UploadFileRequestDto uploadFileRequestDto) {
        Boolean result = false;
        // 判断是否已经生成
        try {
            getContractIsExist(createDto.getOrderCode(), ContractTypeEnum.RESCISSION_CONTRACT.getValue());
        } catch (BizException e) {
            if (e.getExceptionCode() != null && e.getExceptionCode() == 104) {
                // 解除协议合同已经存在
                return true;
            }
        }

        String contractCode = null, // 合同编号
                contractName = null, // 合同名称
                failureReason = null; // 失败原因
        boolean isCreated = false; // 是否成功
        try {
            // 数据转换成map
            Map<String, Object> params = this.objectToMap(createDto);
            // 签订时间
            String signedDate = DateUtil.formatDate(createDto.getSignedTime());
            params.put("signedYear", signedDate.split("-")[0]);
            params.put("signedMonth", signedDate.split("-")[1]);
            params.put("signedDay", signedDate.split("-")[2]);
            if ("2.1".equals(createDto.getCostType())) {
                params.put("incom", createDto.getIncom());
                params.put("incomUpper", createDto.getIncomUpper());
                params.put("disburse", "/");
                params.put("disburseUpper", "/");
            } else {
                params.put("disburse", createDto.getDisburse());
                params.put("disburseUpper", createDto.getDisburseUpper());
                params.put("incom", "/");
                params.put("incomUpper", "/");
            }

            // 查询订单所有合同信息
            List<ContractDto> contracts = contractService.getContractByOrderCode(createDto.getOrderCode(), null);
            if (contracts == null || contracts.isEmpty()) {
                throw new BizException("无主合同信息");
            }
            int suffix = 0;
            String mainContractNumber = null;
            Integer guaranteeType = null;
            for (ContractDto contract : contracts) {
                if (contract.getContractType() == ContractTypeEnum.COMMON_CONTRACT.getValue()) {
                    // 主合同号
                    mainContractNumber = contract.getContractCode();
                    params.put("mainContractNumber", mainContractNumber);
                    // 主合同签订时间
                    String mainSignedDate = DateUtil.formatDate(contract.getSignedTime());
                    params.put("mainYear", mainSignedDate.split("-")[0]);
                    params.put("mainMonth", mainSignedDate.split("-")[1]);
                    params.put("mainDay", mainSignedDate.split("-")[2]);
                    guaranteeType = contract.getGuaranteeType();
                } else {
                    //
                    if (contract.getContractCode() == null) {
                        continue;
                    }
                    String[] contractCodeArray = contract.getContractCode().split("-");
                    int contractCodeSuffix = contractCodeArray.length >= 2 ? Integer.parseInt(contractCodeArray[1]) : 0;
                    suffix = suffix < contractCodeSuffix ? ++contractCodeSuffix : suffix;
                }
            }
            suffix = suffix == 0 ? 1 : suffix;
            contractCode = mainContractNumber + "-" + suffix;
            params.put("contractNumber", contractCode);

            // 查询模板  RESCISSION_CONTRACT
            ContractTemplateDto renegeTemplate = contractTemplateService.getEffectiveTemplate(ContractBusinessTypeEnum.EXCLUSIVEL, ContractTypeEnum.RESCISSION_CONTRACT);
            if (renegeTemplate == null) {
                throw new BizException("无模板");
            }
            contractName = renegeTemplate.getName();
            // 模板赋值参数，生成文件
            String finalFilePath = getFinalFilePath();
            FileCreateFromTemplateResult fileFromTemplate = createPDF(
                    fileEhCacheUtil.getTemplate(renegeTemplate.getName(), renegeTemplate.getTemplatePath()),
                    params, finalFilePath);
            if (fileFromTemplate == null || fileFromTemplate.getErrCode() != 0) {
                throw new BizException("模板生成pdf文件失败:" + fileFromTemplate.getMsg());
            }

            //根据甲方公司id查询公司印章信息
            EsignCompanyDto esignCompanyAssetsA = getEsignCompany(createDto.getPartyAId(),
                    EsignCompanyTypeEnum.ASSET_COMPANY.getValue());
            //根据用户身份证号和姓名查询该用户的印章信息
            EsignAccountDto esignAccountB = getEsignAccount(createDto.getPartyBName(), createDto.getPartyBCard());
            // 盖章
            FileDigestSignResult fileDigestSignResult = renegeSignature(renegeTemplate, fileFromTemplate, esignCompanyAssetsA, esignAccountB);
            if (fileDigestSignResult == null) {
                throw new BizException("pdf文件盖章失败");
            }

            // 保存生成的pdf文件(OSS)
            String ossPdfUrl = byte2FileOss(fileDigestSignResult.getStream(), finalFilePath,
                    "molikejiht-" + UUIDUtil.getUUID() + ".pdf", uploadFileRequestDto);
            // 保存数据
            ContractDto contractDto = this.getGenegeContractDto(ossPdfUrl, createDto, renegeTemplate,
                    guaranteeType, contractCode);
            contractService.createContractBatch(Arrays.asList(contractDto));

            File file = new File(fileFromTemplate.getDstPdfFile());
            file.delete();

            isCreated = true;
        } catch (Exception e) {
            String msg = "订单(" + createDto.getOrderCode() + ")退租生成解除协议失败:" + e.getMessage();
            logger.error(msg, e);
            DingTalkUtil.exceptionSend(ACTIVE_EXPLAIN + msg);
            result = false;
            failureReason = e.getMessage() == null ? null : e.getMessage().length() > 300 ? e.getMessage().substring(0, 300) : e.getMessage();
        } finally {
            // 保存日志信息
            ContractLogDto contractLogDto = createContractLog(createDto.getOrderCode(), ContractBusinessTypeEnum.EXCLUSIVEL.getValue(),
                    contractCode, contractName, failureReason, isCreated);
            contractLogService.createContractLog(contractLogDto);
        }

        return true;
    }

    private ContractDto getGenegeContractDto(String ossPdfUrl, ContractRenegeBizCreateDto dto,
                                             ContractTemplateDto contractTemplateDto,
                                             Integer guaranteeType, String contractCode) {
        ContractDto contractDto = new ContractDto();
        contractDto.setContractPath(ossPdfUrl);
        contractDto.setContractCode(contractCode);
        contractDto.setOrderCode(dto.getOrderCode());
        contractDto.setContractType(contractTemplateDto.getTemplateType()); // 合同类型（
        contractDto.setContractStatus(ContractStatusEnum.EFFECTIVE.getValue());
        contractDto.setSignedTime(dto.getSignedTime());
        contractDto.setBusinessType(ContractBusinessTypeEnum.EXCLUSIVEL.getValue());
        contractDto.setIsCreated(IsDeleteEnum.YES.getValue());
        contractDto.setContractTemplateId(contractTemplateDto.getTemplateId());
        contractDto.setContractTemplatePath(contractTemplateDto.getTemplatePath());
        contractDto.setContractName(contractTemplateDto.getName());
        contractDto.setEndTime(null);
        contractDto.setEffectiveTime(dto.getSignedTime().toLocalDate());
        contractDto.setIsEcontract(IsDeleteEnum.YES.getValue());
        contractDto.setGuaranteeType(guaranteeType);
        contractDto.setPartyAId(dto.getPartyAId().intValue());
        contractDto.setPartyAName(dto.getPartyAName());
        contractDto.setPartyBId(dto.getPartyBId().intValue());
        contractDto.setPartyBName(dto.getPartyBName());
        contractDto.setPartyCName(dto.getPartyCName());
        return contractDto;
    }

    /**
     * 退租解除协议盖章
     *
     * @param contractTemplateDto
     * @param fileFromTemplate
     * @param esignCompanyA
     * @param esignAccountB
     * @return
     */
    private FileDigestSignResult renegeSignature(ContractTemplateDto contractTemplateDto,
                                                 FileCreateFromTemplateResult fileFromTemplate,
                                                 EsignCompanyDto esignCompanyA, EsignAccountDto esignAccountB) {
        FileDigestSignResult result = null;

        SignPDFStreamBean signPDFStreamBean = new SignPDFStreamBean();
        signPDFStreamBean.setDstPdfFile(null);
        signPDFStreamBean.setStream(FileEhCacheUtil.file2byte(fileFromTemplate.getDstPdfFile()));

        //合同盖章位置
        String[] posX = contractTemplateDto.getEsignPosX().split(",");
        String[] posY = contractTemplateDto.getEsignPosY().split(",");

        // 合同甲方盖章
        PosBean posBean = new PosBean();
        posBean.setPosPage(contractTemplateDto.getEsignPosPage());// 页码
        posBean.setPosX(Float.parseFloat(posX[0]));// 坐标
        posBean.setPosY(Float.parseFloat(posY[0])); // 坐标
        result = ESignLib.localSignPDFMoliSide(signPDFStreamBean, posBean,
                esignCompanyA.getSealData(), SignType.Single);
        if (result == null) {
            logger.error("甲方盖章失败(FileDigestSignResult is null)！！！" + JSONObject.toJSONString(signPDFStreamBean) + ","
                    + JSONObject.toJSONString(posBean) + "," + SignType.Single);
            return null;
        } else if (result.getErrCode() != 0) {
            logger.error("同甲方盖章失败(" + result.getErrCode() + ":"
                    + result.getMsg() + ")" + JSONObject.toJSONString(signPDFStreamBean) + ","
                    + JSONObject.toJSONString(posBean) + "," + SignType.Single);
            return null;
        }
        // 乙方盖章
        posBean.setPosPage(contractTemplateDto.getEsignPosPage()); // 页码
        posBean.setPosX(Float.parseFloat(posX[1])); // 坐标
        posBean.setPosY(Float.parseFloat(posY[1])); // 坐标
        signPDFStreamBean.setStream(result.getStream());
        result = localSignPDFCustomerSide(result, signPDFStreamBean, posBean, esignAccountB);

        // 合同丙方盖章
        posBean.setPosPage(contractTemplateDto.getEsignPosPage());// 页码
        posBean.setPosX(Float.parseFloat(posX[2]));// 坐标
        posBean.setPosY(Float.parseFloat(posY[2])); // 坐标
        signPDFStreamBean.setStream(result.getStream());
        result = localSignPDFMoliSide(result, signPDFStreamBean, posBean, companySealDataCacheUtil.getPartyCSealData());

        String[] esignEdgesY = contractTemplateDto.getEsignEdgesY().split(",");
        // 甲方骑缝章
        posBean.setPosPage(contractTemplateDto.getEsignEdgesPage());// 页码
        posBean.setPosY(Float.parseFloat(esignEdgesY[0]));
        signPDFStreamBean.setStream(result.getStream());
        result = localSignPDFMoliSideEdges(result, signPDFStreamBean, posBean, esignCompanyA.getSealData());
        // 丙方骑缝章
        posBean.setPosPage(contractTemplateDto.getEsignEdgesPage());// 页码
        posBean.setPosY(Float.parseFloat(esignEdgesY[1]));
        signPDFStreamBean.setStream(result.getStream());
        result = localSignPDFMoliSideEdges(result, signPDFStreamBean, posBean, esignCompanyA.getSealData());

        return result;
    }

}


